Зависимости PHP auto wire

#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
                (
                )

        )

)