New in Symfony 6.4: AutowireLocator and AutowireIterator Attributes
November 16, 2023 • Published by Javier Eguiluz
Symfony 6.4 is backed by:
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
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);
}
}
You can also define aliases for these services and even include optional services
by prefixing the service class with a ?
symbol:
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 28
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')) {
// ...
}
}
}
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
.
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
Second look: brain is soothed.
That's great!