Определения сервисов
Конфигурация – это место, где мы указываем DI-контейнеру, как собирать отдельные сервисы и как связывать их с другими зависимостями. Nette предоставляет очень понятный и элегантный способ достижения этой цели.
Секция services
в конфигурационном файле NEON – это место, где мы
определяем наши пользовательские сервисы и их конфигурации.
Рассмотрим простой пример определения сервиса с именем database
,
который представляет собой экземпляр класса PDO
:
Эта конфигурация приводит к появлению следующего фабричного метода в контейнере DI:
Имена сервисов позволяют ссылаться на них в других частях
конфигурационного файла, используя формат @serviceName
. Если нет
необходимости присваивать сервису имя, можно просто использовать
пулевую точку:
Для получения сервиса из DI-контейнера можно использовать метод
getService()
с именем сервиса в качестве параметра или метод
getByType()
с типом сервиса:
Создание сервиса
Чаще всего мы создаем сервис, просто инстанцируя определенный класс. Например:
Если нам необходимо расширить конфигурацию дополнительными ключами, то определение может быть разложено на несколько строк:
Ключ create
имеет псевдоним factory
, оба варианта
распространены на практике. Однако мы рекомендуем использовать
create
.
В качестве альтернативы аргументы конструктора или метод создания
могут быть записаны в ключе arguments
:
Сервисы не обязательно должны создаваться только простым инстанцированием класса; они также могут возникать в результате вызова статических методов или методов других сервисов:
Заметим, что для простоты вместо ->
, мы используем ::
,
см. выражения. Эти фабричные методы генерируются:
DI-контейнер должен знать тип создаваемого сервиса. Если мы создаем сервис с помощью метода, который не имеет заданного возвращаемого типа, то мы должны явно указать этот тип в конфигурации:
Аргументы
Передача аргументов конструкторам и методам осуществляется аналогично обычному PHP:
Для лучшей читабельности мы можем перечислять аргументы в отдельных строках. В этом формате использование запятых необязательно:
Можно также назвать аргументы, и тогда можно не заботиться об их порядке:
Если вы хотите опустить некоторые аргументы и использовать их значения по умолчанию или вставить функцию с помощью автоподключения, используйте символ подчеркивания:
Аргументами могут быть сервисы, параметры и многое другое, см. средства выражения.
Настройка
В разделе setup
мы определяем методы, которые должны вызываться
при создании сервиса.
На языке PHP это выглядит следующим образом:
Помимо вызовов методов, можно передавать значения в свойства. Добавление элемента в массив также поддерживается, но его необходимо заключать в кавычки, чтобы избежать столкновения с синтаксисом NEON:
В PHP это будет выглядеть так:
В настройке можно также вызывать статические методы или методы
других сервисов. Если необходимо передать текущий сервис в качестве
аргумента, используйте @self
:
Обратите внимание, что для простоты вместо ->
мы используем
::
, см. средства выражения. В результате
формируется следующий фабричный метод:
Средства выражения
Nette DI предоставляет нам исключительно богатые возможности выражения, позволяющие сформулировать практически все, что угодно. В конфигурационных файлах мы можем использовать параметры:
Мы также можем создавать объекты, вызывать методы и функции:
Ссылайтесь на сервисы либо по их имени, либо по типу:
Используйте синтаксис первоклассных вызываемых элементов:
Использовать константы:
Вызовы методов, как и в PHP, можно объединять в цепочки. Для простоты
вместо ->
мы используем ::
:
Эти выражения можно использовать в любом месте при создании сервисов, в аргументах, в секции настройки или параметрах:
Специальные функции
В конфигурационных файлах можно использовать эти специальные функции:
not()
для отрицания значенийbool()
,int()
,float()
,string()
для приведения типов без потерьtyped()
для создания массива всех сервисов заданного типаtagged()
для создания массива всех сервисов с заданным тегом
По сравнению с обычным приведением типов в PHP, например, (int)
,
при приведении типов без потерь будет возникать исключение для
нечисловых значений.
Функция typed()
создает массив всех сервисов определенного типа
(класса или интерфейса). При этом исключаются сервисы с выключенным
автоподключением. Можно указать несколько типов, разделяя их
запятыми.
Также можно автоматически передать массив сервисов определенного типа в качестве аргумента при использовании автоподключения.
Функция tagged()
создает массив всех сервисов с указанным тегом.
Можно перечислить несколько тегов, разделяя их запятыми.
Автоэлектрика
Ключ autowired
позволяет модифицировать поведение
автоподключения для конкретного сервиса. Более подробная информация
приведена в главе, посвященной автоподключению.
Ленивые услуги
Ленивая загрузка – это техника, которая откладывает создание службы до тех пор, пока она действительно не понадобится. Вы можете включить ленивое создание службы глобально в конфигурации для всех служб сразу. Для отдельных сервисов это поведение можно переопределить:
Когда сервис определен как ленивый, запрос к нему из DI-контейнера будет возвращать специальный прокси-объект. Этот прокси выглядит и ведет себя как настоящий сервис, но настоящая инициализация (вызов конструктора и настройка) будет происходить только при первом вызове любого из его методов или свойств.
Ленивая загрузка может быть использована только для пользовательских классов, но не для внутренних классов PHP. Для ее использования требуется PHP 8.4 или более новая версия.
Теги
Теги используются для добавления дополнительной информации к сервисам. Вы можете назначить сервису один или несколько тегов:
Теги также могут иметь значения:
Чтобы получить все услуги с определенными тегами, можно
воспользоваться функцией tagged()
:
В контейнере DI можно получить имена всех сервисов с определенным
тегом с помощью метода findByTag()
:
Режим инжекции
Использование флага inject: true
активизирует передачу
зависимостей через публичные переменные с помощью аннотации inject и методов inject*().
По умолчанию inject
активизируется только для ведущих.
Модификации сервиса
Контейнер DI содержит множество сервисов, добавленных как
встроенными, так и пользовательскими расширениями.
Определения этих сервисов можно изменять непосредственно в
конфигурации. Например, можно изменить класс сервиса
application.application
, который условно называется
Nette\Application\Application
, на другой:
Флаг alteration
является информативным и указывает на то, что мы
просто модифицируем существующий сервис.
Мы также можем дополнить настройку:
При перезаписи сервиса может потребоваться удалить исходные
аргументы, элементы настройки или теги, и здесь пригодится
reset
:
Если необходимо удалить сервис, добавленный расширением, это можно сделать следующим образом: