New in Symfony 6.4: AutowireLocator and AutowireIterator Attributes
Contributed by
Kevin Bond
and Nicolas Grekas
in #51392
and #51832.
Sometimes, services need access to several other services without being sure
that all of them will actually be used. Injecting all services can hurt
performance (because Symfony will instantiate all of them, even unused ones)
and injecting the entire container is strongly discouraged in Symfony applications.
The best solution in those cases is to use service subscribers and locators.
A service locator is like a custom service container that only includes the
services that you selected.
In Symfony 6.4 we’re improving service locators so you can also define them
using PHP attributes instead of configuration files. The new #[AutowireLocator]
attribute takes a single service ID or an array of service IDs as its first argument:
use AppCommandHandlerBarHandler;
use AppCommandHandlerFooHandler;
use PsrContainerContainerInterface;
use SymfonyComponentDependencyInjectionAttributeAutowireLocator;
class SomeService
{
public function __construct(
#[AutowireLocator([FooHandler::class, BarHandler::class])]
private ContainerInterface $handlers,
) {
}
public function someMethod(): void
{
$fooService = $this->handlers->get(FooHandler::class);
}
}
You can also define aliases for these services and even include optional services
by prefixing the service class with a ? symbol:
use AppCommandHandlerBarHandler;
use AppCommandHandlerFooHandler;
use PsrContainerContainerInterface;
use SymfonyComponentDependencyInjectionAttributeAutowire;
use SymfonyComponentDependencyInjectionAttributeAutowireLocator;
use SymfonyContractsServiceAttributeSubscribedService;
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‘)) {
// …
}
}
}
Check out the #[AutowireLocator] source to learn about its other arguments,
such as $indexAttribute, $defaultPriorityMethod, $exclude, etc.
If you prefer to receive an iterable instead of a service locator, replace
the AutowireLocator attribute by AutowireIterator.
Symfony Blog