[Прежде чем начать, позвольте мне сказать, что я в основном программист на Java - только с небольшим знанием PHP. Но я просто попытаюсь изложить наиболее важные концепции без языковой специфики.]
Внедрение зависимостей основано на двух частях кода:
- Строительство
- Исполнение
В самой крайней форме, в части 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
несколько раз с разными аргументами.