Озадачен внедрением зависимостей в PHP (цепочки классов) - PullRequest
2 голосов
/ 12 января 2012

Я перехожу из Globals and Singletons (= плохо?) В Dependency Injection (= хорошо?) В 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); 

Не слишком ли это уже много?

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

Следующий вопрос - что, если мне нужно зарегистрировать идентификатор пользователя в моем FrontPageController? Я не передавал экземпляр «User» в 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" мне кажется излишним.

Ответы [ 3 ]

4 голосов
/ 12 января 2012

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

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

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

3 голосов
/ 12 января 2012

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

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

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
..

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

2 голосов
/ 15 января 2012

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

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

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

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

...