another_dream
@another_dream
Backend-разработчик, Laravel/ZF2/Yii2

Рационально ли внедрять зависимости в класс через DI-контейнер, обходя при этом стороной конструктор и сеттеры?

Суть описана в заголовке, но приведу пример.

Правильно ли внедрять зависимости подобным образом?
class A {
    public function __constructor(ContainerInterface $container) {
        $this->container = $container;
    }

    public function foo(): void
    {
        // требуемая зависимость
        /** @var ServiceClass $someService */ 
        $someService = $this->container->get(ServiceClassInterface::class);
        // ... логика
    }
}


Или же стоит извне передавать в конструктор класса нужные нам зависимости, которые мы заранее получили из DI-контейнера?

При отсутствии DI-контейнера, само собой, лучше внедрять через конструктор. Но так как мы используем контейнер, в котором определены интерфейсы с их реализациями, необходимость внедрения каждого сервиса через конструктор отпадает, не так ли?
  • Вопрос задан
  • 455 просмотров
Решения вопроса 2
@Flying
В целом это считается плохой практикой. Приведу ссылку на соответствующий кусок из документации DI контейнера в Symfony: https://symfony.com/doc/current/components/depende...

Доставая зависимости непосредственно из контейнера вы лишаете себя массы преимуществ внедрения зависимостей:
  • Страдает тестируемость класса т.к. вы не можете подменить сервисы на нужные вам во время тестов
  • Вы лишаете себя возможности валидации целостности графа зависимостей в случае если используется компилируемый контейнер (как, например, в Symfony)
  • Вы привносите в класс излишнюю информацию о названиях конкретных сервисов которые вы достаёте из контейнера
  • Вам потребуется дополнительно проверять есть ли каждый из сервисов в контейнере и что же именно вы достали из контейнера (через instanceof)


Уверен что есть и другие факторы, это то что пришло на ум в первую очередь.
Ответ написан
Комментировать
@Fantyk
web developer
Нет, не так. Суть DI в управлении зависимостями, когда я смотрю конструктор - я должен видеть от чего зависит код. Ваш вариант практически не отличается от использования глобальных переменных/сервис локатора.
Все современные контейнеры позволяют забиндить интерфейс с реализацией, плюс автовайринг. Для вас, как программиста, даже проще сразу инжектить нужные вам классы, чем просить их у контейнера.


Принцип инверсии зависимостей (англ. dependency inversion principle, DIP):
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Ваш вариант абсолютно противоречит этому принципу, потому что все ваши классы внезапно начинают зависеть от контейнера, тогда как бизнес логика и даже уровень приложения вообще не должны знать о его существовании.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы