Доступ к контейнеру DI - PullRequest
       33

Доступ к контейнеру DI

9 голосов
/ 24 марта 2010

Я начинаю новый проект и настраиваю базу для работы. Возникло несколько вопросов, и я, вероятно, задам здесь немало, надеюсь, я найду ответы.

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

При кодировании я столкнулся с проблемой. Если класс имеет несколько зависимостей и вы хотите передать несколько зависимостей через конструктор (чтобы их нельзя было изменить после создания экземпляра объекта).

Как вы делаете это, не передавая массив зависимостей, используя call_user_func_array (), eval () или Reflection? Это то, что я ищу:

<?php

class DI
{
    public function getClass($classname)
    {
        if(!$this->pool[$classname]) {
            # Load dependencies
            $deps = $this->loadDependencies($classname);

            # Here is where the magic should happen
            $instance = new $classname($dep1, $dep2, $dep3);

            # Add to pool
            $this->pool[$classname] = $instance;

            return $instance;
        } else {
                return $this->pool[$classname];
        }
    }
}

Опять же, я хотел бы избежать самых дорогостоящих методов вызова класса. Любые другие предложения?

Кроме того, как мне получить доступ к классу DI внутри классов, например, в контроллерах, которым требуется доступ к различным моделям? Должен ли я назвать это статически или передать его каждому классу, который будет требовать этого? Я не думаю, что последняя идея осуществима.

Спасибо всем.

Ответы [ 3 ]

23 голосов
/ 24 марта 2010

[Прежде чем начать, позвольте мне сказать, что я в основном программист на Java - только с небольшим знанием PHP. Но я просто попытаюсь изложить наиболее важные концепции без языковой специфики.]

Внедрение зависимостей основано на двух частях кода:

  1. Строительство
  2. Исполнение

В самой крайней форме, в части Execution нет операторов new. Все они перенесены в строительную часть. (На практике это будет смягчено.)

Все строительство происходит - в строительной части. Создает график объектов, необходимых для выполнения снизу вверх. Итак, давайте предположим, что он должен построить A:

  • A зависит от B, а
  • B зависит от C.

Тогда

  • C строится первым.
  • Тогда B строится с параметром C.
  • Тогда A строится с параметром B.

Так что C не нужно передавать в качестве параметра конструктора в A. Этот небольшой пример недостаточно иллюстрирует, насколько это уменьшает количество объектов, которые нужно передать, до довольно небольшого числа.

Сам инжектор зависимостей не должен передаваться в часть выполнения. Это одна из основных ошибок, которые каждый (включая меня) пытается совершить, когда впервые вступает в контакт с DI. Проблема в том, что это полностью размывает границы между конструкцией и исполнением. Другой способ сказать, что это будет нарушать Закон Деметры . Или, если говорить по шаблону: это в конечном итоге «ухудшило бы» шаблон внедрения зависимости до шаблона сервисного локатора. Это спорный вопрос, действительно ли это деградация, но в любом случае обычно это не хорошая идея, чтобы злоупотреблять Dependency Injector как Service Locator .

Таким образом, всякий раз, когда вам нужно дать одному из ваших созданных объектов возможность создавать другие объекты во время выполнения, вместо прохождения инжектора зависимости, вы должны передавать только простых провайдеров (термин, используемый в инфраструктуре Java DI Guice ). Это довольно простые классы, которые могут создавать только определенный тип объектов. У них есть сходство с фабрикой.

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

Итак, подведем итог:

  • Построение объектов снизу вверх.
  • Передайте только столько зависимостей, сколько требуется для создания объекта.
  • Когда вы закончите, начните выполнение.
  • Во время выполнения вы все еще можете извлекать вновь созданные объекты с помощью провайдеров.

Но не стоит забегать слишком далеко: простые объекты все еще можно создавать без провайдера: -)

И теперь все, что вам нужно сделать, это перевести этот материал в качественный код. Может быть, другие могут помочь вам с несколькими примерами PHP.

Приложение: немного больше о провайдерах

Как отмечалось выше, понятие «Поставщик» (специализированная фабрика) немного специфично для структуры Java DI Guice. Эта структура может автоматически создавать провайдера для любого типа объекта. Тем не менее, концепция в целом полезна для DI. Единственное отличие состоит в том, что без помощи Guice или подобного фреймворка вам придется самостоятельно писать провайдеров, но это довольно просто:

Скажем, B зависит от C.

  • Если B просто нужен один фиксированный экземпляр C, вам не нужен Provider - вы можете просто создать B с помощью аргумента конструктора C.
  • Если B необходимо создать больше экземпляров C во время выполнения, просто напишите класс с именем CProvider с помощью метода get(), который может создать новый экземпляр C. Затем передайте экземпляр CProvider в конструктор B и сохранить провайдера в поле экземпляра B. Теперь B может вызвать cProvider.get(), когда ему нужен новый экземпляр C.

Поставщики являются частью Строительного кодекса, поэтому вы можете использовать new C(...)! С другой стороны, они не являются частью кода выполнения, поэтому у вас не должно быть никакой логики выполнения.

Конечно,

CProvider можно передавать в несколько конструкторов. Вы также можете написать несколько версий CProvider1, CProvider2, ... - где каждая может создавать разные версии объектов C с разными свойствами. Или вы просто создаете CProvider несколько раз с разными аргументами.

2 голосов
/ 24 марта 2010

Похоже, вы пытаетесь свернуть свой собственный контейнер внедрения зависимостей. Почему бы не использовать тот, который уже существует, например Symfony , Crafty или Sphicy ?

2 голосов
/ 24 марта 2010

Вам следует использовать контейнер IOC для управления своими зависимостями. Хороший контейнер IOC должен позаботиться о передаче зависимостей между зависимыми конструкторами.

Существует вопрос о параметрах контейнера IOC для PHP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...