With Symfony’s DependencyInjection component it is possible to inline service definitions. Inlining a service means to define the service right away, for one-off usage, usually as the argument of another service.

A classic example would be the service which requires an argument, which is in turn also a service. But in order to inject that other service into the main service, you need to first define it as a service - this is where inlining a service is useful!

Here’s a quick code example that explains what we want to achieve here, using the well-known Mailer and NewsletterManager examples from the official Symfony documentation.

Imagine we have a Mailer class that looks like this:

<?php

namespace App\Email;

class Mailer
{
    private $transport;

    public function __construct(string $transport = 'sendmail')
    {
        $this->transport = $transport;
    }
}

And we also have a NewsletterManager service which depends on the Mailer instance:

<?php

namespace App\Email;

class NewsletterManager
{
    private $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }
}

Let’s use YAML to define NewsletterManager as a service and its dependency Mailer as inlined service:

services:
    App\Email\NewsletterManager:
        arguments:
            - !service { class: App\Email\Mailer }

That’s it! You just inlined Mailer service with the help of custom YAML tag service. As you might be guessing !service accepts all options you would normally use with any other service definition. For example, if you want to pass argument $transport to the inlined Mailer service:

services:
    App\Email\NewsletterManager:
        arguments:
            - !service { class: App\Email\Mailer, arguments: [sendmail] }

Or if you have a MailerFactory which instantiates Mailer objects:

<?php

namespace App\Email;

class MailerFactory
{
    public static function create(string $transport = 'sendmail'): Mailer
    {
        return new Mailer($transport);
    }
}
services:
    App\Email\NewsletterManager:
        arguments:
            - !service { class: App\Email\Mailer, factory: [App\Email\MailerFactory, create] }

If you prefer XML, here’s the syntax:

<?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\Email\NewsletterManager">
            <argument type="service">
                <service class="App\Email\Mailer"/>
            </argument>
        </service>
    </services>
</container>

Or if you need a factory in order to instantiate Mailer:

<?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\Email\NewsletterManager">
            <argument type="service">
                <service class="App\Email\Mailer">
                    <factory class="App\Email\MailerFactory" method="create"/>
                </service>
            </argument>
        </service>
    </services>
</container>

That’s all! Of course, you could always use private services to achieve the same goal and they would be removed during the container optimization and cleanup phase by Symfony. Inlined services are just an alternative way and I hope that you learned now how to easily employ that useful feature.