#php #dependency-injection
#php #внедрение зависимостей
Вопрос:
Я пытаюсь создать контейнер для внедрения зависимостей, который мог бы автоматически подключать зависимости, используя подсказки типа. Проблема возникает, когда зависимости имеют свои собственные зависимости. Другими словами, я хочу, чтобы мой контейнер зависимостей мог обрабатывать неограниченное количество вложенных зависимостей.
Например, автоматическое подключение этого класса было бы простым:
class Bar
{
public function __construct(Foobar $foobar)
{
$this->foobar = $foobar;
}
}
class foo
{
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
Теперь, если у bar также есть зависимость, я должен каким-то образом внедрить foobar в bar и только затем bar в foo.
class foobar
{
}
class Bar
{
public function __construct(Foobar $foobar)
{
$this->foobar = $foobar;
}
}
class foo
{
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
Комментарии:
1. Рекурсия определенно была бы полезна. Но на самом деле, почему бы вам не взглянуть на исходный код контейнера, который может это делать, чтобы увидеть, как это делается?
Ответ №1:
Для достижения этого вам нужны две вещи: рекурсия и отражение
Вот рабочий пример:
function instantiate($class_name) {
$reflection = new ReflectionClass($class_name);
$constructor = $reflection->getConstructor();
// If there is no constructor in class, return object as is
if(!$constructor) return $reflection->newInstance();
$dependencies = [];
$params = $constructor->getParameters();
foreach ($params as $param) {
// Check for type hints in constructor
$paramType = $param->getClass();
if($paramType) {
// If there are type hints, call this very function
// again (recursion) in order to fetch dependency
$dependencies[] = instantiate($paramType->name);
}
}
// Return object (resp. dependency if in recursion loop)
// while also passing required constructor parameters
return $reflection->newInstanceArgs($dependencies);
}
$foo = instantiate('foo');
Если вы напечатаете_r($ foo), вы увидите, что объект ‘foo’ содержит его зависимости.
foo Object
(
[bar] => Bar Object
(
[foobar] => foobar Object
(
)
)
)