2012-01-12 3 views
2

Я перехожу из Globals и Singletons (= bad?) В Injections of Dependency (= good?) В PHP, и я очень к этому знаком.Понравилось с впрыском зависимостей в 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" кажется мне излишним.

+0

Связанные: http://stackoverflow.com/questions/4603555/how-to-deal-with-constructor-over-injection-in-net/4603666#4603666 –

ответ

4

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

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

Взгляните на один или более из следующих признаков:

+0

спасибо! Я попробую один из предлагаемых вами контейнеров DI. – oyatek

+1

Я прочитал документацию по Symphony DI и выглядит не лучше, чем просто универсальный глобальный шаблон «Registry». Мы возвращаемся туда, откуда пришли. Скажи мне, если я ошибаюсь. Какая разница? – oyatek

+1

Я не могу объяснить это где-нибудь рядом, как и Мартин Фаулер, поэтому я позволю ему это сделать ;-) http://martinfowler.com/articles/injection.html –

3

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

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

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

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

+0

поэтому, когда я нахожусь внутри FrontPageModel, и мне нужен доступ к базе данных, я должен назвать $ this-> factory-> getSql() -> getRow ('select id, name from items')? – oyatek

+0

Да, если вы хотите :) Если линия слишком длинная, вы можете хранить детали внутри переменных, получить более короткие строки кодера. – MatejB

+1

Некоторые люди предпочитают не использовать переменные, имеющие все в одной строке. Я сам расколою его. '$ this-> factory-> getSql() -> getRow ('select id, name from items')' слишком длинный. Я бы предпочел '$ sql = $ this-> factory-> getSql(); $ row = $ sql-> getRow ('select id, name from items'); ' – MatejB

2

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

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

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

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

+0

1)« Сделайте шаг в сторону от утечки технической информации »- вы имеете в виду, что я должен использовать __construct (модель FrontPageModel $) вместо просто __construct ($ модель)? 2) «Еще об ответственности. Неужели пользователю действительно нужно все это сделать?» - Сделать что*? :) Я вводил объект «Пользователь», потому что мне нужно знать, зарегистрирован ли текущий пользователь или нет, сколько прав у него есть для определенной страницы и т. Д. Да, он сам создает и обновляет (редко). – oyatek

+1

@oyatek 1) Я предлагаю использовать __construct (BusinessName $ businessImplementation). Какие имена вы бы использовали, если бы ваша мать должна была прочитать код и понять это? Будет ли она заботиться о том, на каком уровне вашего уровня MVC она читает или что вы показываете страницу с информацией о пользователе и дискуссионной нитью? На вашей главной странице не заботятся ни об этих слоях. Он просто хочет отображать UserInformation. 2) Проверка того, входит ли пользователь в систему, несет ответственность за что-то другое, чем FrontPage. – koen

+0

за ответы! :) – oyatek

Смежные вопросы