Озадаченный вложением инъекций в PHP (цепочки классов)

Я перехожу из Globals и Singletons (= bad?) В Injections of Dependency (= good?) В PHP, и я очень к этому знаком.

Я уже много читал много связанных тем по переполнению стека, но я до сих пор не могу понять основные принципы DI.

Скажите, пожалуйста, если я делаю это правильно (это просто сокращенный псевдокод):

// first connect to DB $sql = new Sql(); // create logger (I'm writing logs to Database so I need to pass $sql to it) $log = new Log($sql); // restore logged in user, get info about user, unread messages... // class "User" needs access to Database and Logs: $user = new User($sql, $log); // now we need to collect all the data of current section of my Website // I'm using Model and Controller: $model = new FrontPageModel($sql, $user, $log); $pageController = new FrontPageController($model); 

Хотя на этом этапе это может выглядеть нормально, но что, если мне нужно получить доступ к большему количеству классов, таких как Config, Session и т. Д.?

Должен ли мой код трансформироваться?

 $model = new FrontPageModel($sql, $user, $log, $config, $session); 

Разве это уже не слишком много?

Я знаю, что кто-то может советовать использовать какой-то большой класс «Приложение» и поместить объекты Config, Session, Log, Db внутри этого класса, но я чувствую, что это не очень хорошая идея.

Следующий вопрос – что, если мне нужно получить идентификатор пользователя внутри моего FrontPageController? Я не передал экземпляр «Пользователь» в FrontPageController, но он был передан ранее (в цепочке) в FronPageModel.

 class FrontPageController{ private $model; function __construct($model){ $this->model = $model; } function getData(){ echo $this->model->user->id; // is it right way? } } 

Это «$ this-> model-> user-> id» кажется мне излишним.

Solutions Collecting From Web of "Озадаченный вложением инъекций в PHP (цепочки классов)"

Это может быть не самое красивое, но вы, конечно, не делаете это «неправильно». Вы демонстрируете инъекцию конструктора классов, но, возможно, вы можете реорганизовать, чтобы некоторые из разрозненных объектов были отделены друг от друга.

Мое предложение было бы посмотреть на установленные контейнеры PHP DI. Посмотрите, как они работают, используют их в нескольких приложениях и (1) у вас будет гораздо больше тестируемых приложений, и (2) вам будет намного комфортнее использовать DI в целом.

Взгляните на одно или несколько из следующего:

  • Прыщ
  • Aura DI
  • Symfony DI

Как и все радостные вещи, это зависит.

Я бы поместил все в заводской класс или несколько фабричных классов для разных подсистем.

 class AppFactory { protected $_sql; public function getSql() { if (!empty($this->_sql)) return $this->_sql; $this->_sql = new Sql(); } } 

Затем запустите его при запуске приложения. При необходимости настройте.

 $factory = new AppFactory(); // set config // $factory->internallyGenerateSingletons = true; 

И теперь любой другой класс может его использовать. И, конечно, у вас есть инъекция, чтобы положить завод внутрь.

 $model = new FrontPageModel($factory); // or // $model->useFactory($factory); 

По поводу другого вопроса. Правильно ли это.

 ... $this->model->user->id ... 

Я бы сказал, что все в порядке, но тесто должно использовать такие методы:

 ... $this->model->getUser()->id .. 

Таким образом, вы можете издеваться над классом пользователя при проведении модульного тестирования. И это делает приложение более гибким.

Похоже, у вас есть идея правильной инъекции. Вы даже ставите под вопрос идею Symfonies о DI (в комментарии), которая показывает более зрелое понимание.

Следующим шагом к решению вопросов, которые у вас есть, является отвлечься от утечки технической информации с одного слоя на другой. Например, вашим контроллерам все равно, что они разговаривают с моделью. Ваша модель не заботится о том, чтобы она говорила о базе данных sql или nosql.

Другое дело об ответственности. Действительно ли пользователю нужно все это сделать? Отвечает ли пользователь за ведение журнала? Это может быть правильный выбор, но также кажется, что вы просите его сделать многое. Создает ли пользователь сам себя, обновляет себя? и т.д

$this->model->user->id; // is it right way? Не правильный путь. 1) Это очень сильная связь. 2) вам нужен идентификатор пользователя? пользователь только вводит в качестве зависимости, чтобы получить что-то от него? возможно, что-то вроде $this->user->showUserInfo($userInfoDisplay) можно использовать?