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