Symfony includes tens of PHP attributes so you can define metadata next to your code. In Symfony 7.1 we've added some new attributes and in this article we'll showcase two of them related to the DependencyInjection component.

AutowireMethodOf Attribute

Nicolas Grekas
Contributed by Nicolas Grekas in #54016

Consider a Symfony controller that needs to call a getCommentPaginator() method from a Doctrine repository called CommentRepository. You could inject the repository class in the controller action or its constructor. Another alternative is to use the existing #[AutowireCallable] attribute to do this:

1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\DependencyInjection\Attribute\AutowireCallable;
use App\Repository\CommentRepository;

class SomeController
{
    public function showComments(
        #[AutowireCallable(service: CommentRepository::class, method: 'getCommentPaginator')]
        \Closure $getCommentPaginator,
    ) {
        // ...
    }
}

In Symfony 7.1 we're introducing a new AutowireMethodOf attribute to simplify this even more:

1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\DependencyInjection\Attribute\AutowireMethodOf;
use App\Repository\CommentRepository;

class SomeController
{
    public function showComments(
        #[AutowireMethodOf(service: CommentRepository::class)]
        \Closure $getCommentPaginator,
    ) {
        // ...
    }
}

The method name is inferred from the argument name so you don't need to define it explicitly as in #[AutowireCallable]. Moreover, if you defined an interface like this:

1
2
3
4
interface GetCommentPaginatorInterface
{
    public function __invoke(Conference $conference, int $page): Paginator;
}

The previous example could be refactored like this:

1
2
#[AutowireMethodOf(CommentRepository::class)]
GetCommentPaginatorInterface $getCommentPaginator,

The benefits of the new #[AutowireMethodOf] attribute are:

  • Increased flexibility: it allows injecting specific methods as Closures, providing greater control over what functionality is injected;
  • Improved readability: thanks to the attribute, the intention behind the dependency injection is made explicit, improving code clarity;
  • Enhanced modularity: it decouples services from direct dependencies on specific class methods, making the codebase more maintainable and testable.

AutowireInline Attribute

Ismail Özgün Turan Nicolas Grekas
Contributed by Ismail Özgün Turan and Nicolas Grekas in #52820

Service autowiring allows you to manage services in Symfony applications with minimal configuration. However, sometimes some services need some manual configuration. In current Symfony applications, you must define that configuration in YAML, XML or PHP format in a file stored in config/.

In Symfony 7.1 we're introducing an #[AutowireInline] attribute so you can define services right inside the related PHP class. Consider the following service:

1
2
3
4
5
6
7
8
9
10
class SomeSourceAwareLogger
{
    public function __construct(
        private readonly LoggerInterface $logger,
        private readonly string $someSource,
    ) {
    }

    // ...
}

To inject this service in another one and configure its constructor arguments, you no longer have to edit the services configuration file. You can use the #[AutowireInline] attribute as follows:

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\DependencyInjection\Attribute\AutowireInline;
// ...

class SomeClass
{
    public function __construct(
        #[AutowireInline(class: SomeSourceAwareLogger::class, args: [new Reference(LoggerInterface::class), 'bar'])]
        public SomeSourceAwareLogger $someSourceAwareLogger,
    ) {
    }
}

If you have defined a factory, use the factory option of the attribute to define the details:

1
2
3
4
5
6
7
8
9
10
11
12
class SomeClass
{
    public function __construct(
        #[AutowireInline(
            class: SomeSourceAwareLogger::class,
            factory: [SomeSourceAwareLoggerFactory::class, 'staticCreate'],
            args: [new Reference(LoggerInterface::class), 'someParam'],
        )]
        public SomeSourceAwareLogger $someSourceAwareLogger,
    ) {
    }
}

Using these new attributes is completely optional. If you don't like them or they don't fit your application for any reason, you can keep injecting the dependencies and defining the services in the configuration file as before.

Published in #Living on the edge