Замыкания сервисов

Дата обновления перевода 2025-02-24

Замыкания сервисов

Эта функция оборачивает внедряемый сервис в замыкание, позволяя ему лениво загружаться, когда и если это необходимо. Это полезно, если внедряемый сервис требует больших усилий для инстанцирования или используется только в некоторых случаях. Сервис инстанцируется при первом
вызове замыкания, а все последующие вызовы возвращают один и тот же экземпляр,
если только сервис не является общим:

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)();
    }
}
Чтобы определить замыкание сервиса и внедрить его в другой сервис, создайте аргумент
типа service_closure:
1
2
3
4
5
6
7
# config/services.yaml
services:
    App\Service\MyService:
        arguments: [!service_closure '@mailer']

        # В случае, если зависимость не является обязательной
        # arguments: [!service_closure '@?mailer']

See also

Замыкания сервисов можно внедрять с помощью автомонтирования . и специальных атрибутов.

See also

Другой способ ленивого внедрения сервисов - через локатор сервиса.

Использование замыкания сервиса в передаче компилятора

В передаче компилятора вы можете создать замыкание сервиса, обернув ссылку на сервис в экземпляр 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')));
}