进一步了解OOP和类,我有一个非常大的用户类,管理起来变得越来越大。总代码超过950行,完全驳回了单一责任原则。
我认为使这个更小的几种方法是创建完全独立的类并在构造新类时传输数据。例如:
的index.php
$user = new user('username');
$userOptions = new userOptions($user);
或
$user = new user;
$userOptions = new userOptions;
$userOptions->setData(
$user->getData([
'username'=>'genericuser'
]),
);
然而,这似乎并不自然,并且不像我期望的格式正确的代码那么好。
我想到的另一种方法是将基类扩展到另一个基类。例如:
的index.php
$userOptions = new userOptions('username');
类/ useroptions.php
class userOptions extends User {
//a small section of what would be a big user class
}
然而,这也违反了一些PHP做法,extends
通常意味着 的一个特例,用户选项似乎并不存在。
我组织文档的最后一种方法是在默认类中使用大文件,例如:
类/ user.php的
class User {
/**
* CREATION SECTION
*/
public function create() {
//create user
}
/**
* UPDATE SECTION
*/
public function change($whattochange) {
//what to change
}
}
然而,这又一次似乎违反了单一责任原则,在一个单一的课程中有很多选择。
分类课程的常见做法是什么,应该如何完成?
当前的User类内部有以下方法:
* - $variables
* - __construct gets a new user.
* - stripeCustomer() gets the customer information if it exists
* - create($fields|array) method to create a new user
* - login($username|string, $password|string, $remember|bool) logs in a user
* - find ($param|string, $method|string) finds a user WHERE param=method
* - data() returns user data
* - isLoggedIn() returns whether a user is logged in
* - isAdmin() returns if a user is an admin
* - logout() logs out current user
* - displayName() returns first name or username
* - isVerified() checks if a user is verified
* - inCompany() checks if a user is in a company
* - inVerifiedCompany() checks if a user id in a verified company
* - verifyUser($apicode|string, $verification|string, $resend|bool) verifies a users email
* - error() returns any errors that may occur
* - getProfilePicture($size|int) gets a users profile picture from Gravatar with size of $size in pixels
* - passwordCheck($password|string) checks if two passwords match
*
* // 2FA section
* - has2FA() checks if the user has 2FA enabled
* - TOTP($type|string, $secret|string, $code|string, $backupcodes|array) everything to do with 2FA
* - countBackups() counts the amount of backup codes remaining for a user with 2FA
* - update($statement|string, $params|array, $apicode|string) updates a user
*
* // lockdown system
* - getAttempts() gets amount of attempts to break into a users account
* - isLocked() gets whether the user account is locked
* - addAttempt() adds an attempt to a users account
* - reinstateUser() unlocks a users account
* - shouldShowCaptcha() checks whether a captcha is needed
*
* // codes
* - sendRequest($code|int) sends a request to a users email with a specific code
* - verifyCode($code|string, $type|int) checks a user inputted code to one in the DB
*
* - deleteUser() deletes the specific user
* - makeAdmin() makes the user an admin
* - removeAdmin() removes the user as an admin
* - modify($changes|array, $apicode|string) modifies a user | no idea how this is different to update
我也明白该类的数据库部分应该是一个单独的映射器类,它将使用与我最初尝试相同的样式结构,这将很快改变。
提前感谢您的帮助。
作为参考,我已经看过google,发现有些人会问类似的问题,但似乎没有人在很大程度上回答这个问题。 How to break up a large class
答案 0 :(得分:1)
有一种称为trait
的方法,你可以制作任意数量的特征,然后在一个类中包含..制作单独的特征文件,它将使你的代码易于阅读..
什么trait
实际上它就像一个有很多方法的类。
如何使用它
语法将是这样的..
trait UserOptions{
public function create()
{
// logic goes here
}
public function destroy(){
// logic
}
}
trait UserAdmin{
public function isAdmin(){
return true;
}
}
class User{
// this is how to include traits
use UserOptions , UserAdmin ;
}
现在所有特征的所有方法都包含在User类中。 这就是我们如何分解这么多代码
答案 1 :(得分:1)
嗯,我自己并不是真正的专家。但我想问题的答案有两个方面。一个不是真正的技术。让我们从它开始。
重构不是一项微不足道的任务。重构遗留代码是两次(我不确定你的代码实际上是遗留代码,但我认为规则成立)。通常由他们所在领域的专家来完成。甚至在他们开始之前,还有几个步骤要做。首先,必须记录系统的当前行为。使用某种end-to-end (acceptance) tests或通过非常详尽的技术文档(由business analytics完成)。两者都更好。只有这样你才能开始重写过程。如果没有这个,你根本无法确定系统是否会像以前一样工作。这是最好的情况,你最终会得到明确的错误(你可以立即清楚地看到)。但是你也可能会遇到一些意想不到的隐含行为,你可能会在一段时间后才注意到这一点。
关于技术方面。现在你有了所谓的God object。它至少有persistence,authentication和authorization。所以你说SRP (Single responsibility principle)完全被驳回了。首先,您必须提取实体(业务对象):
final class User
{
private $id;
private $name;
// ...
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function id()
{
return $this->id;
}
public function name()
{
return $this->name;
}
}
然后提取repository以保留此实体:
final class UserRepository
{
/**
* \PDO or whatever connection you use.
*/
private $db;
public function __construct(\PDO $db)
{
$this->db = $db;
}
public function findByPk($id): User {}
public function create(User $user) {}
public function update(User $user) {}
public function delete(User $user) {}
}
将身份验证和授权提取到单独的服务中。更好的是,使用现有的软件包(你可以在GitHub上找到很多软件包。)
但是,只有当你有办法确保你的改变没有破坏任何东西时,所有这一切都是安全的。
这个主题有一个book。说实话,我还没有自己看过,但我已经和作者一起听了播客,并听到了很好的评论。所以你可以看一下。
答案 2 :(得分:0)
您应该考虑使用迁移过程重新设计,而不是拼接烂软件。最好的方法是创建一个新的分支,可以处理旧的数据结构,但允许引入新的(直的)。干净的切割也比许多小的迁移步骤更好。两者都有风险:小步骤需要很长时间,每一步都会导致用户沮丧。切割可能会失败,您可能需要回滚。