Внедрение зависимостей (также Dependency injection или DI) — механизм подстановки фреймворком зависимостей для конструктора или других методов у создаваемых объектов.
При создании объектов фреймворком, таких, как контроллеры, middlewares, команды и другие, внедрение зависимостей уже назначено при вызове целевого метода (в том числе конструктора).
Согласно механизму DI предполагается, что если указать в зависимостях (аргументах) метода нужные в нём классы или интерфейсы, то фреймворк попытается найти такие соответствия в контейнере, получит из контейнера или самостоятельно создаст объект и подставит его в необходимый аргумент.
При этом, если в контейнере такой сервис найден не будет, то будет произведена попытка создать объект из обычного подходящего класса в проекте, а если у последнего есть свои зависимости в конструкторе, то фреймворк попробует их наполнить аналогичным образом.
При отсутствии подстановочного значения для аргументов, которые имеют значения по умолчанию, будет использовано дефолтное.
Иначе фреймворк вернёт ошибку с информацией, что успешно использовать DI для указанных зависимостей не удалось.
Когда объект контроллера или middleware создается на стороне фреймворка, то сначала разрешаются зависимости конструктора, затем вызываемого метода.
Также, когда запрос обрабатывается фреймворком, то в совпавшем контроллере вызовется только один метод, в таком случае нет разницы, откуда получать зависимость, из конструктора или метода, хотя из конструктора в некоторых случаях удобнее.
На следующем примере показаны два метода контроллера с различным присвоением $logger из контейнера через DI.
Аналогичным образом устанавливаются зависимости для middleware.
В командах фреймворка и в событиях (Events) реализовано похожим образом, но только через конструктор:
Внедрение зависимостей удобно тем, что при тестировании мы можем создать нужные значения для зависимостей класса. Однако, при создании объекта вручную, было бы неудобно инициализировать самим все его зависимости. Чтобы автоматизировать этот процес, существует класс Hleb\Static\DI фреймворка.
Здесь показано, как создать объект класса, в конструкторе которого есть зависимость, а также вызвать нужный метод объекта, в котором также нужно автоматически подставить значение. На примере также есть зависимость не из контейнера (класс Insert), объект которой создается и подстанавливается в метод.
Довольно часто используемый вариант DI c Request и Response (в данном случае получаемых из контейнера):
Из-за существования различных подходов в именовании интерфейсов, получение стандартных сервисов из контейнера может быть как по интерфейсу с окончанием Interface, так и без. Например, Hleb\Reference\RequestInterface аналогичен Hleb\Reference\Interface\Request.
← Получение сервиса Request →