Cover of the book Symfony 5: The Fast Track

Symfony 5: The Fast Track is the best book to learn modern Symfony development, from zero to production. +300 pages in full color showing how to combine Symfony with Docker, APIs, queues & async tasks, Webpack, Single-Page Applications, etc.

Buy printed version
WARNING: You are browsing the documentation for Symfony 4.3 which is not maintained anymore. Consider upgrading your projects to Symfony 5.1.

Service Method Calls and Setter Injection

4.3 version

Service Method Calls and Setter Injection

Tip

If you’re using autowiring, you can use @required to automatically configure method calls.

Usually, you’ll want to inject your dependencies via the constructor. But sometimes, especially if a dependency is optional, you may want to use “setter injection”. For example:

namespace App\Service;

use Psr\Log\LoggerInterface;

class MessageGenerator
{
    private $logger;

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    // ...
}

To configure the container to call the setLogger method, use the calls key:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # config/services.yaml
    services:
        App\Service\MessageGenerator:
            # ...
            calls:
                - method: setLogger
                  arguments:
                      - '@logger'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Service\MessageGenerator">
                <!-- ... -->
                <call method="setLogger">
                    <argument type="service" id="logger"/>
                </call>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Service\MessageGenerator;
    
    return function(ContainerConfigurator $configurator) {
        // ...
    
        $services->set(MessageGenerator::class)
            ->call('setLogger', [ref('logger')]);
    };
    

New in version 4.3: The immutable-setter injection was introduced in Symfony 4.3.

To provide immutable services, some classes implement immutable setters. Such setters return a new instance of the configured class instead of mutating the object they were called on:

namespace App\Service;

use Psr\Log\LoggerInterface;

class MessageGenerator
{
    private $logger;

    /**
     * @return static
     */
    public function withLogger(LoggerInterface $logger)
    {
        $new = clone $this;
        $new->logger = $logger;

        return $new;
    }

    // ...
}

Because the method returns a separate cloned instance, configuring such a service means using the return value of the wither method ($service = $service->withLogger($logger);). The configuration to tell the container it should do so would be like:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # config/services.yaml
    services:
        App\Service\MessageGenerator:
            # ...
            calls:
                - method: withLogger
                  arguments:
                      - '@logger'
                  returns_clone: true
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Service\MessageGenerator">
                <!-- ... -->
                <call method="withLogger" returns-clone="true">
                    <argument type="service" id="logger"/>
                </call>
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // config/services.php
    use App\Service\MessageGenerator;
    use Symfony\Component\DependencyInjection\Reference;
    
    $container->register(MessageGenerator::class)
        ->addMethodCall('withLogger', [new Reference('logger')], true);
    

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.