Как получить экземпляр контейнера PHP-DI из любого класса, который я хочу?

Я использую контейнер PHP-DI 6 в своем проекте PHP. В самом начале моей программы я просто инициализирую контейнер и получаю класс Application со всеми внедренными зависимостями.

    $container   = new Container();
    $application = $container->get(Application::class);

    $application->initialize();
    $application->run();

На изображении ниже вы можете увидеть классы, которые я использую в своем проекте.

диаграмма классов

Диспетчер Asterisk внедряется в класс Application.

private $asteriskDispatcher;

public function __construct(AsteriskDispatcher $asteriskDispatcher)
{
    $this->asteriskDispatcher = $asteriskDispatcher;
}

Затем внутри класса AsteriskDispatcher мне нужно создать список экземпляров Asterisk Manager, который также будет содержать некоторые зависимости в ближайшем будущем.

Я не хочу наследовать контейнер через все классы. Есть ли способ инициализировать контейнер PHP-DI как синглтон, чтобы я мог использовать его в любой момент, когда захочу создать какие-то объекты?

Вот как я это делаю прямо сейчас, я просто создаю новый экземпляр контейнера PHP-DI внутри своего класса AsteriskDispatcher, и это выглядит чертовски ужасно.

class AsteriskDispatcher implements AsteriskDispatcherInterface
{
    private $listOfAsteriskManagers;

    public function __construct()
    {
        $configurations = AsteriskConnectionsConfiguration::$connectionsConfiguration;

        $this->listOfAsteriskManagers = new \SplDoublyLinkedList();

        $container = new Container();

        foreach ($configurations as $configuration)
        {
            $this->listOfAsteriskManagers->push($container->make(AsteriskManager::class,
                array('configuration' => $configuration)));
        }
    }
}

Я действительно хочу понять, как я могу использовать контейнер PHP-DI, не нарушая принципов SOLID.


person NanoBreaker    schedule 14.01.2019    source источник


Ответы (1)


Из документации:

Если вам нужно использовать метод make() внутри службы, или контроллера, или чего-то еще, рекомендуется указать тип FactoryInterface *. Это позволит избежать привязки вашего кода к контейнеру. DI\FactoryInterface автоматически привязывается к DI\Container, поэтому вы можете внедрить его без какой-либо настройки.

*курсив мой

Итак, вы должны изменить свой конструктор AsteriskDispatcher так:

public function __construct(FactoryInterface $factory) {
  // your code ...
  // more of your code ...

  $factory->make(AsteriskManager::class, ['configuration' => $configuration]);

  // the rest of your code.

}

PS: Singletons зло (в основном).

person yivi    schedule 14.01.2019
comment
А что, если мне нужен экземпляр контейнера в моей начальной загрузке, который является функциональным кодом? Насколько я знаю, контейнер может внедряться только в код ООП. - person Gabor Garami; 04.01.2020
comment
Извините, но я не понимаю. Не могу вам помочь. - person yivi; 04.01.2020