Skip to content

Service Closures

Warning: You are browsing the documentation for Symfony 6.2, which is no longer maintained.

Read the updated version of this page for Symfony 7.2 (the current stable version).

Service Closures

This feature wraps the injected service into a closure allowing it to be lazily loaded when and if needed. This is useful if the service being injected is a bit heavy to instantiate or is used only in certain cases. The service is instantiated the first time the closure is called, while all subsequent calls return the same instance, unless the service is not shared:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/Service/MyService.php
namespace App\Service;

use Symfony\Component\Mailer\MailerInterface;

class MyService
{
    /**
     * @param callable(): MailerInterface
     */
    public function __construct(
        private \Closure $mailer,
    ) {
    }

    public function doSomething(): void
    {
        // ...

        $this->getMailer()->send($email);
    }

    private function getMailer(): MailerInterface
    {
        return ($this->mailer)();
    }
}

To define a service closure and inject it to another service, create an argument of type service_closure:

1
2
3
4
5
6
7
# config/services.yaml
services:
    App\Service\MyService:
        arguments: [!service_closure '@mailer']

        # In case the dependency is optional
        # arguments: [!service_closure '@?mailer']

See also

Another way to inject services lazily is via a service locator.

Using a Service Closure in a Compiler Pass

In compiler passes you can create a service closure by wrapping the service reference into an instance of ServiceClosureArgument:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

public function process(ContainerBuilder $container): void
{
    // ...

    $myService->addArgument(new ServiceClosureArgument(new Reference('mailer')));
}
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version