Внедрение зависимостей (Dependency Injection, DI) — это шаблон проектирования, при котором объект получает свои зависимости из внешних источников, а не создаёт их самостоятельно. Основная идея заключается в том, чтобы отделить создание зависимостей объекта от его основной функциональности. Это способствует модульности, гибкости, тестируемости и слабой связанности различных частей программы.
Ключевые концепции внедрения зависимостей:
1. Зависимости: Объекты или сервисы, от которых зависит другой объект для выполнения своей функции. Например, класс может зависеть от подключения к базе данных или от сервиса логирования.
2. Внедрение: Вместо того чтобы создавать зависимости внутри класса, они передаются (внедряются) извне, как правило, через:
• Конструктор: Зависимости передаются через конструктор класса.
• Сеттеры: Зависимости передаются через методы-сеттеры.
• Интерфейсы: Зависимости передаются путём реализации интерфейса, который требует внедрения.
3. Инверсия управления (IoC): Внедрение зависимостей — это форма инверсии управления, при которой управление созданием объектов передаётся из класса во внешний источник, обычно в контейнер внедрения зависимостей (DI-контейнер) или контейнер сервисов. Этот контейнер разрешает и внедряет зависимости.
Пример внедрения зависимостей:
Ниже приведён пример, показывающий, как работает внедрение зависимостей в PHP с использованием внедрения через конструктор.
Без внедрения зависимостей:
В этом примере класс UserService создаёт экземпляр Database самостоятельно, что делает его жёстко связанным с этим классом. Если вы захотите использовать другой класс для работы с базой данных, вам придётся изменять класс UserService.
С внедрением зависимостей:
Теперь класс UserService не создаёт собственный экземпляр Database, а получает его извне. Это делает класс более гибким, так как вы можете внедрить разные типы объектов Database по мере необходимости.
Преимущества внедрения зависимостей:
1. Слабая связанность: Зависимый класс не нуждается в знании о том, как создаются его зависимости. Это приводит к более гибкому и поддерживаемому коду.
2. Тестируемость: Внедрение зависимостей позволяет легко заменять реальные зависимости на тестовые заглушки или мок-объекты во время тестирования, что упрощает написание юнит-тестов.
3. Принцип единственной ответственности (SRP): Классы не отвечают за создание и управление своими зависимостями, что соответствует принципу SRP. Они сосредотачиваются на своей основной функциональности.
4. Гибкость: Внедрение зависимостей позволяет изменять или заменять зависимости без изменения зависимого класса, что способствует повторному использованию и гибкости кода.
Контейнер внедрения зависимостей (DI-контейнер):
В больших приложениях ручное управление зависимостями может стать сложным. DI-контейнер автоматизирует этот процесс, управляя созданием и внедрением зависимостей.
Пример с DI-контейнером (на основе контейнера сервисов Symfony):
Контейнер автоматически создаёт экземпляр Database и внедряет его в класс UserService.
Типы внедрения зависимостей:
1. Внедрение через конструктор: Зависимости передаются через конструктор класса. Это наиболее распространённый тип, так как он гарантирует наличие зависимостей при создании объекта.
2. Внедрение через сеттеры: Зависимости передаются через методы-сеттеры. Это позволяет использовать необязательные зависимости, но может привести к тому, что объект будет создан без всех необходимых зависимостей, что потенциально может вызвать проблемы.
3. Внедрение через интерфейс: Класс реализует интерфейс, который требует метода для внедрения зависимостей. Это менее распространённый подход, так как он считается более сложным.
Использование DI в реальном мире:
• Фреймворки, такие как Symfony, Laravel и Zend, активно используют DI для управления сервисами и компонентами.
• Тестирование и мокирование: DI облегчает замену реальных сервисов на тестовые во время тестирования.
Внедрение зависимостей в Drupal:
В Drupal внедрение зависимостей (DI) стало ключевой концепцией, начиная с версии 8, так как Drupal построен на основе фреймворка Symfony. Drupal использует контейнер сервисов для управления зависимостями и их автоматического внедрения в различные классы и сервисы, что повышает гибкость, тестируемость и поддерживаемость вашего кода.
Основные концепции внедрения зависимостей в Drupal:
1. Контейнер сервисов: Централизованный контейнер, в котором хранятся доступные сервисы (объекты, выполняющие определённые задачи). Контейнер автоматически разрешает и внедряет зависимости по мере необходимости.
2. Сервисы: Повторно используемые объекты, выполняющие конкретные задачи (например, логирование, подключение к базе данных или рендеринг). Эти сервисы определяются в контейнере и внедряются по мере необходимости.
3. Внедрение через конструктор: В Drupal наиболее распространённый способ внедрения зависимостей — через конструктор. Зависимости передаются в класс через его конструктор.
Пример внедрения зависимостей в Drupal:
Предположим, что вам нужно внедрить сервис в собственный блок или контроллер.
Шаг 1: Создание сервиса:
Сначала определите сервис, который вы хотите внедрить.
my_module.services.yml:
Сервис my_module.custom_service определяется в файле services.yml. Он ссылается на класс CustomService, а его зависимость (сервис логирования) передаётся как аргумент (@logger.channel.default).
Шаг 2: Создание класса сервиса:
src/Service/CustomService.php:
Этот класс сервиса зависит от сервиса логирования, который внедряется через конструктор.
Шаг 3: Внедрение сервиса в блок:
Теперь создадим блок, который использует этот сервис.
src/Plugin/Block/MyCustomBlock.php:
Основные моменты:
• create(ContainerInterface $container): Этот статический метод использует контейнер сервисов для получения зависимостей. В данном случае он получает my_module.custom_service.
• Внедрение через конструктор: Объект CustomService передаётся через конструктор класса блока, что позволяет его использовать в методе build().
Как работает внедрение зависимостей в Drupal:
• Контейнер сервисов: Drupal использует контейнер сервисов Symfony. Сервисы определяются в файлах *.services.yml и автоматически внедряются туда, где они нужны.
• ContainerFactoryPluginInterface: При создании блоков, форм, контроллеров или других типов плагинов в Drupal вы можете реализовать этот интерфейс для использования внедрения зависимостей.
Дополнительные примеры внедрения зависимостей в Drupal:
1. Внедрение сервисов в контроллер:
2. Внедрение сервисов в формы:
Вы также можете внедрять сервисы в формы, реализуя интерфейс FormInterface и используя ContainerFactoryPluginInterface для внедрения зависимостей.
Преимущества использования внедрения зависимостей в Drupal:
1. Слабая связанность: Классы и сервисы не зависят друг от друга напрямую, что делает код более модульным и легко поддерживаемым.
2. Тестируемость: DI упрощает тестирование классов, так как можно передавать мок-объекты во время тестов, не полагаясь на реальные реализации сервисов.
3. Повторное использование: Сервисы могут быть повторно использованы в разных частях приложения, что улучшает повторное использование кода.
4. Гибкость: Зависимости можно легко заменять, что даёт большую гибкость коду. Например, можно внедрять разные сервисы в зависимости от окружения (например, для разработки или для продакшена).
Наиболее часто внедряемые сервисы в Drupal:
• Сервис логирования: @logger.channel.default для логирования сообщений.
• Менеджер типов сущностей: @entity_type.manager для работы с сущностями.
• Подключение к базе данных: @database для взаимодействия с базой данных.
• Фабрика конфигураций: @config.factory для получения конфигураций.
• Messenger: @messenger для отображения сообщений пользователям.
Заключение:
В Drupal внедрение зависимостей улучшает модульность и гибкость приложения, позволяя внедрять сервисы по мере необходимости. Оно использует контейнер сервисов Symfony для разрешения зависимостей и их внедрения в блоки, контроллеры, формы и любые другие классы. Этот шаблон способствует использованию лучших практик, таких как слабая связанность и тестируемость кода.
Нужен профессиональный сайт на Drupal?
Ищете разработчиков для создания сайта на Drupal? Мы предлагаем профессиональные услуги по разработке сайтов на Drupal любой сложности