New in Symfony 7.3: Dependency Injection Improvements


Symfony 7.3 introduces several enhancements to the DependencyInjection component
that simplify service configuration, make autoconfiguration more flexible, and
enable environment-specific aliasing.

Service Closure Shorthand

Contributed by
chx
in
#59257

Service closures wrap the injected service into a closure allowing it to be
lazily loaded only when needed. This is useful when the injected service is
expensive to instantiate or only used in specific cases.
When using YAML config, you had to use the custom !service_closure tag to
inject service closures. In Symfony 7.3, we've added a shortcut to configure
these service closures
:

# config/services.yaml
services:
# this is the traditional way of defining service closures
App\Service\MyService:
arguments: [!service_closure '@mailer']

# in case the dependency is optional
# arguments: [!service_closure '@?mailer']

# '@>' is the new shortcut to define service closures
App\Service\AnotherService:
arguments: ['@>mailer']

# the shortcut also works for optional dependencies
# arguments: ['@>?mailer']

Defining Aliases per Environment

Contributed by
Zuruh
in
#60186

Service aliasing lets you create an alternative ID for existing services.
They're useful for defining shortcuts, renaming services without removing the
original ones, and more.
In Symfony 7.3, we're improving service aliases so you can define aliases only
on certain environments
. This is useful for example to create aliases only
in the test configuration environment for testing purposes:

// src/Some/Service.php
namespace App\Some;

// ...
use Symfony\Component\DependencyInjection\Attribute\AsAlias;

#[AsAlias(id: 'app.foo', when: 'test')]
class Service
{
// ...
}

You can pass more than one environment name if needed:

#[AsAlias(id: 'app.foo', when: ['dev', 'test'])]

Resource Tags


Contributed by
Jérôme Tamarelle
and Kevin Bond
in
#59704
and #60011

Sometimes you want to exclude certain classes like model classes, entities,
etc. from service autoconfiguration. However, this prevents tagging those
classes with a service tag and later using methods like findTaggedServiceIds()
to find them.
In Symfony 7.3, we've improved the service container so you can find tagged
classes even if they are not registered as services
. For example, suppose
your application defines a PHP attribute called #[AppModel], which you
apply to all model classes that should not be registered as services.
Then, in a service container extension, you can use autoconfiguration to
find all classes with that PHP attribute and apply a tag to them using
the new addResourceTag() method:

$this->registerAttributeForAutoconfiguration(AppModel::class, static function (ChildDefinition $definition) {
// this is the new method introduced in Symfony 7.3
$definition->addResourceTag('app.model');

// there's no need to apply the following tag because it's automatically
// applied by Symfony for you to not register these classes as services
// $definition->addTag('container.excluded');
});

Related to this change, Symfony 7.3 also improves the
registerAttributeForAutoconfiguration() method, allowing you to call it
multiple times for the same PHP attribute. Previously, it could only be called
once per attribute.
Later, in a compiler pass, you can find these classes using the new
findTaggedResourceIds() method:

$classes = [];
foreach($containerBuilder->findTaggedResourceIds('app.model') as $id => $tags) {
$classes[] = $containerBuilder->getDefinition($id)->getClass();
}

// save the list of classes as a container parameter to retrieve it later
$containerBuilder->setParameter('.app.model_classes', $classes);

Symfony itself now uses resource tags. If you check the service configuration
of your Symfony applications, you'll probably find the following exclude lines:

# config/services.yaml
services:
# ...

App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'

Starting in Symfony 7.3, these default exclude lines are no longer necessary.
Thanks to the new resource tags introduced in this version, service container
extensions, test cases, Doctrine entities, and Messenger messages are now
automatically tagged and excluded for you.

Special thanks to Jérôme for helping review the contents of this post.

Sponsor the Symfony project.