Изучая ООП и классы, я имею чрезвычайно большой пользовательский класс, который становится все более и более большим, чтобы им управлять. Общий код превышает 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 и обнаружил, что некоторые люди задают подобные вопросы, однако ни один из них не отвечает на этот вопрос в значительной степени.
Как разбить большой класс
есть способ, который называется 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.
Вот как мы можем сломать так много кода
Ну, я на самом деле не эксперт. Но я думаю, что ответ на вопрос имеет две стороны. Один не очень технический. Начнем с этого.
Рефакторинг не является тривиальной задачей. Рефакторинг унаследованного кода выполняется дважды (я не уверен, что ваш код на самом деле унаследован, но, думаю, это правило выполняется). Обычно это делают люди, которые являются экспертами в своей области. И даже до того, как они начнутся, нужно сделать пару шагов. Во-первых, текущее поведение системы должно быть задокументировано. Либо с каким-то сквозные (приемочные) испытания или действительно тщательной технической документацией (сделано бизнес-аналитика). Лучше с обоими. И только тогда вы можете начать процесс переписывания. Без этого вы просто не можете быть уверены, что система будет работать как прежде. В лучшем случае вы получите явные ошибки (те, которые вы можете сразу увидеть). Но вы также можете столкнуться с неожиданным неявным поведением, которое вы можете заметить только через некоторое время.
Что касается технической стороны. Теперь у вас есть так называемый Бог объект. Это по крайней мере упорство, аутентификация а также авторизация. Так как вы заявили SRP (принцип единой ответственности) полностью уволен. Итак, сначала вы должны извлечь сущность (бизнес-объект):
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;
}
}
Затем извлечь хранилище чтобы сохранить эту сущность:
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).
Но опять же, все это безопасно сделать, только если у вас есть способ убедиться, что ваши изменения ничего не сломали.
Eсть книга на предмет. Честно говоря, я еще не читал его сам, но я слушал подкаст с автором и слышал действительно хорошие отзывы. Таким образом, вы можете проверить это.
Вместо того, чтобы сшивать гнилое программное обеспечение, вы должны подумать о редизайне с процессом миграции. Лучше всего создать новую ветку, которая может справляться со старыми структурами данных, но позволяет вводить новые (прямые). Чистый срез также лучше, чем многие маленькие этапы миграции. В обоих случаях есть риск: маленький шаг занимает много времени, и каждый может вызвать разочарование пользователя. Разрез может потерпеть неудачу, и вам, возможно, придется откатиться назад.