New in Symfony 2.8: Service Auto Wiring

Contributed by
Kévin Dunglas
in #15613.

The Dependency Injection component is one of the most important elements of the Symfony applications. This component allows developers to configure services in YAML, XML or PHP files and let Symfony create those services for them.

Services usually define an arguments option listing the arguments passed to their constructors. If the application contains the following two classes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
namespace AppBundle\Service;

class Service1
{
}

namespace AppBundle\Service;

use AppBundle\Service\Service1;

class Service2
{
    private $service1;

    public function __construct(Service1 $service1)
    {
        $this->service1 = $service1;
    }
}

The needed YAML configuration would be the following:

1
2
3
4
5
6
7
8
# app/config/services.yml
services:
    service1:
        class: AppBundle\Service\Service1

    service2:
        class: AppBundle\Service\Service2
        arguments: ['@service1']

In Symfony 2.8, thanks to the new service auto wiring feature, you can skip the definition of service1. The reason is that the service container is able to introspect the constructor parameters, create a private service for Service1 class and inject it into service2.

This feature is disabled by default and its behavior is restricted to the cases where the services can be guessed unequivocally. You just need to set the new autowire option to true in the services where you want auto wire and let the service container do the rest.

This is how the same service configuration shown before looks like when using auto wiring (service1 isn't defined explicitly and service2 doesn't define its arguments):

1
2
3
4
5
# app/config/services.yml
services:
    service2:
        class: AppBundle\Service\Service2
        autowire: true

Service auto wiring was pioneered more than 10 years ago by the Spring Java framework with their @Autowired annotation and it's a feature best suited for simplifying the development of application prototypes.

Comments

http://nooooooooooooooo.com/
user AppBundle\Service\Service1

should be "user AppBundle\Service\Service1"

"use" instead of "user"

Oskar
@Frank fixed! Thanks.
Although this definitively will reduce the amount of work on crafting you services in the DIC, I think I want my services clearly defined in my services definition. Less amount of magic. Great work do!
I agree with @Jorge and what about performance, how this affects the performance of?
@Marek: Performances at runtime are not impacted at all. The autowiring thing happens in a compiler pass, and the compiled container is cached to be reused.
I'm not fan of this feature neither, but I understand the convenience for RAD.
Awesome news, thanks for the option!
@Jorge Luis Betancourt: Correct me if I'm wrong but in this case you can still define Service1, you just don't have to define all the arguments of Service2 which is very useful if you have services which are modified very often and it's easy to forget to update its definititions in configuration(and that way new fatal error in app is born :P).

+1 from me for this feature.
If the use statement and class name is "AppBundle\Service\Service1" shouldn't the namespaces for these classes just be "AppBundle\Service" ?

And if that's the case, then the use statement is even redundant.

Regarding the actual functionality, is it aware of aliases not actually being another service implementing the same class?
@Matt I've fixed some minor issues. The "use" is not strictly necessary, but it's used to better illustrate the code of the example.
It will indeed decrease the amount of work spent in services definition but as @Jorge I don't think I'll use it, too much magic for me :) ! Anyway, good job.
Finally
Good job, awesome!
@Maxime thanks for clarification about performance, I understand the convenience for RAD too but still not fan of this :) I want find services defined always on same place. But great work for those who need it.
But services should rely on interfaces, to follow the SOLID principles and be easily replaceable.
So, as the article correctly says: it's a feature for prototypes.
@Andrei if you read a bit more up on the feature you'll find it does support interfaces also, and that you can also define defaults for case where you have several implementations of the same interface.

It is a nice feature for smaller projects where there are not that many services, but I agree it tends to be a bit too much magic.
Just one question, will I see auto wired service in result of php app/console container:debug ?
@Marek yes, because of this pull request: https://github.com/symfony/symfony/pull/16469
Does auto wiring applies on the nested dependencies also?

i.e. What if there is a Service3 that depends on Service2 that depends on Service1?

Will only this be sufficient?

# app/config/services.yml
services:
service3:
class: AppBundle\Service\Service3
autowire: true
Perhaps a use case would be useful
What about default routing/service configuration formats ?
I used to (thanks to what i've learned from sensio team) configure routing with annotation and services as xml.
The bundle generator in 2.8 always set yml as services configuration… Is this format the new best practice ?

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.