Новое в Symfony 6.4: Атрибуты AutowireLocator и AutowireIterator

Источник: «AutowireLocator and AutowireIterator Attributes»
В Symfony 6.4 вводится новый атрибут AutowireLocator, позволяющий определять локаторы сервисов с помощью PHP атрибутов, а не конфигурационных файлов.

Иногда сервисам требуется доступ к нескольким другим сервисам без уверенности в том, что все они действительно будут использоваться. Инъекция всех сервисов может снизить производительность (поскольку Symfony будет инстанцировать все сервисы, даже неиспользуемые), поэтому инъекция всего контейнера в приложениях Symfony категорически не рекомендуется.

Лучшим решением в таких случаях является использование подписчиков и локаторов сервисов. Локатор сервиса — это контейнер пользовательских сервисов, включающий только те сервисы, которые вы выбрали.

В Symfony 6.4 мы усовершенствовали локаторы сервисов, теперь их можно определять не через конфигурационные файлы, а с помощью PHP атрибутов. Новый атрибут #[AutowireLocator] принимает в качестве первого аргумента один идентификатор сервиса или массив идентификаторов сервисов:

use App\CommandHandler\BarHandler;
use App\CommandHandler\FooHandler;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;

class SomeService
{
public function __construct(
#[AutowireLocator([FooHandler::class, BarHandler::class])]
private ContainerInterface $handlers,
) {
}

public function someMethod(): void
{
$fooService = $this->handlers->get(FooHandler::class);
}
}

Вы также можете определить псевдонимы для этих служб и даже включить дополнительные службы, добавив к классу службы символ ?:

use App\CommandHandler\BarHandler;
use App\CommandHandler\FooHandler;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
use Symfony\Contracts\Service\Attribute\SubscribedService;

class SomeService
{
public function __construct(
#[AutowireLocator([
'foo' => FooHandler::class,
'bar' => new SubscribedService(type: 'string', attributes: new Autowire('%some.parameter%')),
'optionalBaz' => '?'.BazHandler::class,
])
]

private ContainerInterface $handlers,
) {
}

public function someMethod(): void
{
$fooService = $this->handlers->get('foo');

if ($this->handlers->has('optionalBaz')) {
// ...
}
}
}

Ознакомьтесь с исходным кодом #[AutowireLocator], чтобы узнать о других его аргументах, таких как $indexAttribute, $defaultPriorityMethod, $exclude и т.д.

Если вы предпочитаете получать не локатор сервиса, а итератор, замените атрибут AutowireLocator на AutowireIterator.

Дополнительные материалы

Предыдущая Статья

Обновление синтаксиса CSS вложенности

Следующая Статья

DatePoint: Новый класс иммутабельной даты/времени для Symfony 6.4