Як працювати з обʼєктами визначень сервісу

Дата оновлення перекладу 2022-11-25

Як працювати з обʼєктами визначень сервісу

Визначення сервісу - це інструкції, які описують те, як контейнер повинен побудувати сервіс. Вони не є сервісами, використовуваними вашими додатками. Контейнер створить справжні екземпляри класу, засновуючись на конфігурації у визначенні.

Зазвичай ви би використовували YAML, XML або PHP, щоб описати визначення сервісу. Але якщо ви робите з сервіс-контейнером просунуті речі, на кшталт роботи з Пропуском компілятора або створення Розширення впровадження залежності, вам може знадобитися працювати напряму з обʼєктами Definition, які визначають те, як буде інстанційовано сервіс.

Отримавання та установка визначень сервісу

Існує декілька корисних методів для роботи з визначеннями сервісу:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\DependencyInjection\Definition;

// дізнається, чи є визначення "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'), // посилання на інший сервіс
    '%app.config_table_name%',  // буде розвʼязано до значення параметра контейнера
]);

// отримує всі аргументи, сконфігуровані для цього визначення
$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', [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, що означає, що ваш файл буде включено лише один раз у кожному запиті.