Я использовал контейнер Dice PHP DI довольно долгое время, и он кажется лучшим с точки зрения простоты инъекционных зависимостей.
Из документации на кости :
class A { public $b; public function __construct(B $b) { $this->b = $b; } } class B { } $dice = new \Dice\Dice; $a = $dice->create('A'); var_dump($a->b); //B object
Однако, когда вам приходится использовать объекты, которые напрямую зависят друг от друга, конечным результатом является ошибка сервера из-за бесконечного цикла .
Пример:
class A { public $b; public function __construct(B $b) { $this->b = $b; } } class B { public $a; public function __construct(A $a) { $this->a = $a; } }
Автор Dice говорит, что нет способа построить объект из классов A или B. В виде:
Автор говорит, что это ограничение касается всех контейнеров DI !
Что было бы лучшим решением для успешного преодоления этой проблемы без изменения исходного кода? Может ли кто-нибудь представить пример использования других контейнеров DI , когда можно было бы запустить примерный код без громоздких обходных решений?
Как упоминалось в вашем сообщении на Dice github ( https://github.com/TomBZombie/Dice/issues/7 ), единственный способ разрешить без удаления круговой зависимости – это рефакторинг одного из классов для использования инъекции установщика:
class A { public $b; public function __construct(B $b) { $this->b = $b; } } class B { public $a; public function setA(A $a) { $this->a = $a; } }
Это позволяет создавать объекты:
$b = new B(); $a = new A($b); $b->setA($a);
С исходным кодом:
class A { public $b; public function __construct(B $b) { $this->b = $b; } } class B { public $a; public function __construct(A $a) { $this->a = $a; } }
Вы не можете построить его и столкнуться с той же проблемой, что и контейнер:
$b = new B(new A(new B(new A(new B(.............))))
Проблема с использованием контейнера вокруг этой проблемы с использованием взлома, такого как ReflectionClass :: newInstanceWithoutConstructor, заключается в том, что ваши объекты теперь зависят от логики создания, которая использует этот метод. Вы по существу соединяете код с контейнером, который является плохим дизайном, поскольку ваш код теперь не переносится и не может использоваться без контейнера для выполнения объекта.
У вас есть круговая зависимость, которую очень трудно решить. Первое, что нужно сделать, это попытаться избавиться от этой циклической зависимости , рефакторинг ваших классов и их взаимодействие.
Если вы действительно не можете этого сделать, есть решения. Я скопирую мой ответ из моделей саморегуляции. Максимальный уровень вложенности функции x в Laravel 4 :
Вместо того, чтобы вводить зависимость в конструкторе, вы можете ввести его в сеттер, который будет вызываться после создания объекта. В псевдокоде это будет выглядеть так:
$userRepo = new UserRepository(); $cartRepo = new CartRepository($userRepo); $userRepo->setCartRepo($userRepo);
Я не знаю, поддерживает ли Dice ленивую инъекцию, но это также решение: контейнер будет вводить прокси-объект вместо фактической зависимости. Этот прокси-объект будет загружать зависимость только тогда, когда к ней обращаются, тем самым устраняя необходимость создания зависимости при вызове конструктора.
Вот объяснение того, как ленивая инъекция работает, если вы заинтересованы: http://php-di.org/doc/lazy-injection.html