@7876010

Dependency Injection Container, попробовал на практике — не понял смысла?

Всем привет, начал изучать паттерн dependency injection, вроде, все понятно и логично.

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

Очень долгое время я не мог понять, как же используется этот контейнер на практике, какая область видимости у контейнера, и в какой момент в контейнер добавляют сервисы ?

Задав эти вопросы на форумах, мне посоветовали взять любой DI-контейнер, и попробовать с ним поработать, тогда и станет понятно.

Решил я взять очень простой DI-контейнер, от разработчиков symfony - Pimple.

Написал класс SystemBlock (системный блок) с 3-4 зависимостями:

  • Блок питания
  • Видеокарта
  • Процессор
  • Операционная система


Пример вызова класса SystemBlock без контейнера:

<?php
use Less\SystemBlock;
 
$systemBlock = new SystemBlock\SystemBlock(
    new SystemBlock\GigabytePower,
    new SystemBlock\GeForceVideo,
    new SystemBlock\IntelProcessor
);
 
 
$os = new SystemBlock\LinuxOS;
$os->setUser(new SystemBlock\OSUser("Вася", "Vasya", true));
 
$systemBlock->setOperatingSystem($os);
$systemBlock->start();


и пример с использованием контейнера:
<?php
use Less\SystemBlock;
 
$container = new \Pimple\Container;
 
$container["power"] = function ($c) {
    return new SystemBlock\GigabytePower;
};
 
$container["video"] = function ($c) {
    return new SystemBlock\GeForceVideo;
};
 
$container["processor"] = function ($c) {
    return new SystemBlock\IntelProcessor;
};
 
$container["system_block"] = function ($c) {
    return new SystemBlock\SystemBlock(
        $c["power"],
        $c["video"],
        $c["processor"]
    );
};
 
$systemBlock = $container["system_block"];
 
$os = new SystemBlock\LinuxOS;
$os->setUser(new SystemBlock\OSUser("Вася", "Vasya", true));
 
$systemBlock->setOperatingSystem($os);
$systemBlock->start();


Файлы с классами и интерфейсами выложил на GitHub

Возникшие вопросы:

1. Правильно ли я понял, что сервисы в контейнер мы добавляем в файле единой точки входа в приложение ?

Что делать, если у меня у случая, когда нужно вызвать нужный сконфигурированный сервис загрузки товаров на сайт, например:
1.1. Загрузка происходит через файл bin/import.php при запуске скрипта через крон.
1.2. При загрузка происходит через админку admin/import.php сайта по кнопке.

В первом и втором случае мне необходим один и тот же сконфигурированный сервис. Мне необходимо в начале каждого файла bin/import.php и admin/import.php добавлять сервисы в контейнер и конфигурировать, или нужно вынести в отдельный общий файл ? Покажите пример пожалуйста, как это делается, и какие могут быть нюансы ?

. Из моих примеров управления зависимостями через контейнер и вручную, я не заметил никакой разницы. В чем преимущество контейнера ? Почему то, что я сделал вручную - неудобно ?

или контейнер нужен в тех случаях, когда один и тотже сервис используется несколько раз ? И в будущем удобно будет тестировать ? Заменил только в контейнере на тестовый сервис ?

И честно говоря, для меня самое сложное - это понять пункт

В каком месте приложения нужна инициализация контейнера ? Можно ли выносить в отдельный файл? Как подключать этот файл ? И т.д.

Я задал этот же вопрос на другом форуме, где меня еще больше запутали, и теперь я не знаю, прав ли участник форума, который хочет мне помощь, или нет..

Уже долгое время не могу одолеть эту тему..
  • Вопрос задан
  • 304 просмотра
Решения вопроса 1
Maksclub
@Maksclub Куратор тега PHP
maksfedorov.ru
Контейнер
Главная задача контейнера — переиспользовать сервисы более одного раза, например некий провайдер более чем в 1 месте или некий Sender в 20 местах по всему приложению. И упростить к ним доступ.

Более того именно контейнер помогает упростить некоторые другие участки приложения, например роутер, когда мы регистрируем роуты и их хэндлеры (контроллеры), то строим приложение таким образом, что все аргументы этих обработчиков и аргументы этих аргументов подтянутся из контейнера, то есть сильно убавят у нас проблем с управлением зависимостей и сделают сам код роутер (да и другой код) сильно проще и надежнее.

Взаимодействие относительно простых объектов/сущностей в рамках одного слоя лучше делать вашим способом — оно логичное и понятное и вообще контейнер будет только мешать, даже больше — не к месту в этой задаче. Это вам в ответе на том форуме и отметили.

Современные контейнеры предоставляют на самом деле еще ооочень много фишек: автовайринг, когда вам и конфиг писать не нужно, просто в конструкторе написали класс, а контейнер если нашел такой класс, то сам и сконфигурирует (и также учтет его параметры конструктора), то есть разработчику остается работа только с уникальными и не стандартными ситуациями.
Или дает упрощенные фабрики/билдеры/декораторы.

Dependency Injection
И в будущем удобно будет тестировать ?

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

Главное не объединяйте эти два понятия. Сам паттерн — просто частный случай инверсии зависимости, класс получил зависимость через конструктор/сеттер, и все, он не знает деталей, потому и тестить проще — просто подменил на пустышку.
А контейнер — средство для работы со сложным приложением, которое внедряет как раз таки, то есть выполняет работу внедрения. Центральное в нем — слово контейнер.

Несколько точек входа
По поводу ваших точек входа: несколько точек входи = несколько иницализаций.
Как-бы они разные по своей сути приложения уже по определению получаются.
Но вы можете упростить, и вынести инициализацию контейнера в абстракцию — в некий класс App/Kernel и там это делать, а в точке входа инициализировать не контейнер раз за разом, а именно конкретное приложение.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@postgresdev
В общем не читал вопрос.
Когда нужно протестировать код: тебе нужно подменять объякты для того чтоб не тестировать зависимости(при юнит тестах). То есть у тебя будет жесткая связь.
Плюс если у Вас есть опыт, прочитайте 150 страниц совершенного кода, все встанет по местамю.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
от 150 000 до 180 000 руб.
N1.RU Новосибирск
от 100 000 руб.
16 сент. 2019, в 19:16
50000 руб./за проект
16 сент. 2019, в 18:39
2000 руб./за проект
16 сент. 2019, в 18:30
3000 руб./за проект