Как работать с объектами определений сервиса
Дата обновления перевода 2023-06-30
Как работать с объектами определений сервиса
Определения сервиса - это инструкции, описывающие то, как контейнер должен построить сервис. Они не яляются сервисами, используемыми вашими приложениями. Контейнер создаст настоящие экземпляры класса, основываясь на конфигурации в определении.
Обычно, вы бы использовали YAML, XML или PHP, чтобы описать определения сервиса.
Но если вы делаете с сервис-контейнером продвинутые вещи, вроде работы с
Передачей компилятора или создания
Расширения внедрения зависимости, вам может понадобиться
работать напрямую с объектами Definition
, который определяют то, как будет
инстанциирован сервис.
Получение и установка определений сервиса
Существует несколько полезных методов для работы с определениями сервиса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// узнать, есть ли определение "app.mailer"
$container->hasDefinition('app.mailer');
// узнать, если определения или дополнительного имени "app.mailer" нет
$container->has('app.mailer');
// получить определение "app.user_config_manager"
$definition = $container->getDefinition('app.user_config_manager');
// получить определение с ID или дополнительным именем "app.user_config_manager"
$definition = $container->findDefinition('app.user_config_manager');
// добавить новое определение "app.number_generator"
$definition = new Definition(\App\NumberGenerator::class);
$container->setDefinition('app.number_generator', $definition);
// шорткат для предыдущего метода
$container->register('app.number_generator', \App\NumberGenerator::class);
Работа с определением
Создание нового определения
В дополнение к изменению и получению существующих определений, вы также можете определять новые определения сервиса с классом Definition.
Класс
Первый необязательный аргумент класса Definition
- это полностью квалифицированное
имя класса объекта, возвращённого, когда сервис вызывается из контейнера:
1 2 3 4 5 6 7 8 9 10 11
use App\Config\CustomConfigManager;
use App\Config\UserConfigManager;
use Symfony\Component\DependencyInjection\Definition;
$definition = new Definition(UserConfigManager::class);
// переопределить класс
$definition->setClass(CustomConfigManager::class);
// сделать так, чтобы для этого определения был сконфигурирован класс
$class = $definition->getClass();
Аргументы конструктора
Второй необязательный аргумент класса Definition
- это массив с аргументами,
переданными конструктору объекта, возвращённого, когда сервис вызывается из
контейнера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
use App\Config\DoctrineConfigManager;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$definition = new Definition(DoctrineConfigManager::class, [
new Reference('doctrine'), // a reference to another service
'%app.config_table_name%', // will be resolved to the value of a container parameter
]);
// получить все аргументы, сконфигурированные для этого определения
$constructorArguments = $definition->getArguments();
// получить конкретный аргумент
$firstArgument = $definition->getArgument(0);
// добавить новый именованый аргумент
// '$argumentName' = имя аргумента в конструкторе, включая символ '$'
$definition = $definition->setArgument('$argumentName', $argumentValue);
// добавить новый аргумент
$definition->addArgument($argumentValue);
// заменить аргумент конкретным индексом (0 = первый аргумент)
$definition->replaceArgument($index, $argument);
// заменить все ранее сконфигурированные аргументы переданным массивом
$definition->setArguments($arguments);
Caution
Не используйте get()
, чтобы получить сервис, который вы хотите
внедрить в качестве аргумента конструктора, сервис ещё не доступен.
Вместо этого, используйте экземпляр Reference
,как показано выше.
Вызовы метода
Если сервис, с которым вы работаете, использует сеттер-внедрение, тогда вы также можете изменить любые вызовы метода в определении:
1 2 3 4 5 6 7 8 9 10 11
// получить все сконфигурированные вызовы метода
$methodCalls = $definition->getMethodCalls();
// сконфигурировать новый вызов метода
$definition->addMethodCall('setLogger', array(new Reference('logger')));
// сконфигурировать неизменяемый сеттер
$definition->addMethodCall('withLogger', [new Reference('logger')], true);
// заменить все созданные ранее вызовы метода переданным массивом
$definition->setMethodCalls($methodCalls);
Tip
Существует больше примеров конкретных способов работы с определениями
в блоках PHP-кода в статьях о Сервис-контейнере, например,
Использование фабрики для создания сервисов и Как управлять общими зависимостями с родительскими сервисами.
Note
Методы здесь, который изменяют определения сервиса, могут быть использованы только перед тем, как будет скомпилирован контейнер. Как только контейнер скомпилирован, вы больше не сможете изменять определения сервиса. Чтобы узнать больше о компиляции контейнера, смотрите Компиляция контейнера.
Требование файлов
Могут быть случаи, когда вам понадобится включить другой файл прямо перед тем, как будет загружен сам сервис. Чтобы сделать это, вы можете использовать метод setFile():
1
$definition->setFile('/src/path/to/file/foo.php');
Отметьте, что Symfony внутренне вызовет PHP-утверждение require_once
,
что означает, что ваш файл будет включён только единожды в каждом запросе.