Новое в Symfony 6.4: Атрибуты AutowireLocator и AutowireIterator
- Pull Request: [DependencyInjection] add #[AutowireLocator] attribute #51392 Kevin Bond
- Pull Request: [DependencyInjection] Add #[AutowireIterator] attribute and improve #[AutowireLocator] #51832 Nicolas Grekas
Иногда сервисам требуется доступ к нескольким другим сервисам без уверенности в том, что все они действительно будут использоваться. Инъекция всех сервисов может снизить производительность (поскольку 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
.