Я начинаю новый проект и создаю базу для работы. Несколько вопросов поднялись, и я, вероятно, буду спрашивать здесь немало, надеюсь, что найду ответы.
Первый шаг – обрабатывать зависимости для объектов. Я решил пойти с шаблоном проектирования инъекций зависимостей, к которому я несколько недавно, для обработки всего этого для приложения.
Когда на самом деле это кодирование, я столкнулся с проблемой. Если класс имеет несколько зависимостей, и вы хотите передать несколько зависимостей через конструктор (чтобы они не могли быть изменены после создания экземпляра объекта).
Как вы это делаете, не передавая массив зависимостей, используя 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 внутри классов, например, в контроллерах, которым требуется доступ к различным моделям? Должен ли я называть его статически или передавать его по каждому классу, который потребует его? Я не думаю, что последняя идея возможна.
Всем спасибо.
[Прежде чем начать, позвольте мне сказать, что я в основном программист на Java – всего лишь немного знаний PHP. Но я просто попытаюсь использовать самые важные понятия без специфики языка.]
Инъекция зависимостей основана на двух частях кода:
В самой экстремальной форме в части Execution нет new
операторов. Все они перемещаются в конструкцию. (На практике это будет уменьшено.)
Вся конструкция происходит – в строительной части. Он создает график объектов, необходимых для выполнения снизу вверх. Итак, допустим, он должен построить A:
затем
Таким образом, C не должен передаваться как параметр конструктора в A. Этот небольшой пример недостаточно иллюстрирует, насколько это уменьшает количество объектов, которые должны быть переданы до довольно небольшого числа.
Сам инжектор зависимостей не должен передаваться в часть выполнения. Это одна из основных ошибок, которые каждый (включая меня) пытается сделать, когда они впервые вступают в контакт с ДИ. Проблема в том, что это полностью размывает линии между строительством и исполнением. Другой способ сказать, что это нарушит Закон Деметры . Или в шаблоне говорят: он в конечном итоге «деградирует» шаблон «Зависимость впрыска» к шаблону «Локатор службы». Это спорный вопрос, действительно ли это деградация, но в любом случае это, как правило , не очень хорошая идея , чтобы злоупотреблять Dependency Injector как локатором.
Поэтому всякий раз, когда вам нужно дать одному из ваших сконструированных объектов возможность создавать другие объекты во время выполнения, вместо передачи инжектора зависимостей, вы будете передавать только простые провайдеры (термин, используемый средой Java DI Guice ). Это довольно простые классы, которые могут создавать только определенный объект. Они имеют сходство с фабрикой.
Сначала попробуйте передать необходимые зависимости непосредственно конструктору.
Итак, подведем итог:
Но не заходите слишком далеко: простые объекты могут быть созданы без провайдера 🙂
И теперь все, что вам нужно сделать, это перевести этот материал в качественный код. Возможно, другие могут помочь вам с несколькими примерами PHP.
Добавление: Немного больше о Провайдерах
Как отмечалось выше, понятие «Провайдер» (специализированная фабрика) немного специфично для Java DI framework Guice. Эта структура может автоматически создавать Провайдера для любого типа объекта. Однако эта концепция, как правило, полезна для DI. Единственное различие заключается в том, что без помощи Guice или аналогичной структуры вам придется сами писать Провайдеры, но это довольно просто:
Предположим, что B зависит от C.
CProvider
с помощью метода get()
, который может создать новый экземпляр C. Затем передайте экземпляр CProvider
в конструктор B и сохраните Поставщик в поле экземпляра B. Теперь B может вызвать cProvider.get()
когда ему нужен новый экземпляр C. Провайдеры являются частью кода строительства, поэтому вам разрешено использовать new C(...)
! С другой стороны, они не являются частью кода исполнения, поэтому у вас не должно быть никакой логики выполнения.
CProvider
можно передать в несколько конструкторов. Вы также можете написать несколько версий CProvider1
, CProvider2
, … – каждый из них может создавать разные версии объектов C с различными свойствами. Или вы просто CProvider
экземпляр CProvider
несколько раз с разными аргументами.
Вы должны изучить использование контейнера IOC для управления своими зависимостями для вас. Хороший контейнер IOC должен заботиться о передаче зависимостей между зависимыми конструкторами для вас.
Существует уже существующий вопрос о вариантах контейнера IOC для PHP.
Похоже, вы пытаетесь перевернуть свой собственный контейнер инъекций зависимостей. Почему бы не использовать тот, который уже существует, например, Symfony , Crafty или Sphicy ?