New in Symfony 3.3: Optional class for named services

Contributed by
Martin Hasoň and Nicolas Grekas
in #21133.

Services in Symfony applications are traditionally defined in YAML, XML or PHP configuration files. A typical but simple service definition looks like this in YAML:

1
2
3
4
5
# app/config/services.yml
services:
    app.mailer:
        class:     AppBundle\Mailer
        arguments: [sendmail]

And like this in XML:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="app.mailer" class="AppBundle\Mailer">
            <argument>sendmail</argument>
        </service>
    </services>
</container>

In Symfony 3.3, we're adding some new features to the Dependency Injection component that allow working with services in a different manner. For that reason, in Symfony 3.3, the class argument of the services is now optional. When it's undefined, Symfony considers that the id of the service is the PHP class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
services:
    # ...
    # traditional service definition
    app.manager.user:
        class: AppBundle\EventListener\UserManager
        tags:  ['kernel.event_subscriber']

    # new service definition allowed in Symfony 3.3
    AppBundle\EventListener\UserManager:
        tags:  ['kernel.event_subscriber']

When using this new feature, getting services from the container requires to pass the full PHP namespace:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
use AppBundle\EventListener\UserManager;

// ...
public function editAction()
{
    // ...

    // before Symfony 3.3
    $this->get('app.manager.user')->save($user);

    // Symfony 3.3
    $this->get(UserManager::class)->save($user);

    // ...
}

The traditional service definition will keep working as always (and it's even mandatory to use it in cases like decorating services). However, this new feature together with other optional features such as autowiring and defining default service options per file, will enable RAD ("rapid application development") for those projects and developers that need it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
services:
    # default options applied to all the services in this file
    _defaults:
        # enable autowiring for these services
        autowire: true
        # make services private by default
        public: false

    App\TwigExtension:
        tags: [twig.extension]

    App\Doc:
        tags:
            - { name: twig.runtime, id: "App\\TwigExtension" }

Comments

Nice ! Thanks to the team
Thanks for this new feature!
You put an example of the new service definition in Yaml but not in Xml, maybe you could add it to show people it works too :)
Awesome!
also an example with empty children would be helpful: "App\Controllers: ~"
Thanks for this new feature!
Good one ! Thanks for this feature !
Nice feature, thanks !
Hello, can you also provide the updated exemple using no id for a service declaration in XML.

I'm pretty sure we will have fun with the additional \ to not forget when using class name as id in Service tags properties..
Hello, nice feature.
+1: missing example with XML.
Awesome!
excellent idea ! Thanks !
Nice job!
This feature will only invite people to do everything with this method (faster), and will only obtain "read-only" projects, unable to be overwritten.

Can anyone please tell me what do we gain with this?
Marc, let's be pragmatic here. In a project, you rarely/never have to overwrite your own services (you defined them yourselves, so you can change them as you see fit). But it makes Symfony "feels" simpler as you don't need to come up with a name for all your services, which is cumbersome and not needed. I would even say that choosing a name for a service encourage you to use the container as a service locator. And of course, you can still name your services if you want to. So, no drawbacks, purely optional, and helps newcomers. I see a lot of gains here.
Well, maybe we're turning too pragmatic. I'm as much pragmatic as my experience let me be, and what I see is too much refactoring because these kind of things. I'm agree with most of the things you explained here, but with the named structured way, you're getting away from the equivalent of the "Open/Closed Principle" if we talk about the DIC. Don't focus on what's the easiest way, no matter the collateral damage, otherwise we should preach in favor of the container injection (being pragmatic, you rarely never will test properly the class, at least, in the real world).
Of course, this is my opinion, but don't let Symfony fall in the easy way of doing everything RAD, and focus on DX, improve your code in order to make it accessible for more people and give the community the tools to make this important RAD part of the ecosystem, not part of the core :)
Thanks for the Response, Fabien.
BTW, I've always used Symfony because of these thoughts, because each time someone told me "Symfony is difficult" my answer was... Iddeed, but totally worth it. I would never like to hear that Symfony became easy.
Gold feature
Thanks for another step to autowiring support. This will ease so much pain!
I don't like
-1
Great Feature!! Thanks!
Nice feature but will be better if this App\TwigExtension we can write like App.TwigExtension and like was at previous comment, with no child looks like App.TwigExtension: ~

Comments are closed.

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