Как создавать псевдонимы сервиса и отмечать сервисы, как приватные

Дата обновления перевода 2024-07-27

Как создавать псевдонимы сервиса и отмечать сервисы, как приватные

Отмечание сервисов приватными / публичными

Во время определения сервиса, его можно сделать публичным или приватным. Если сервиса публичный, то это значит, что вы можете получить к нему доступ напрямую из контейнера во время прогона. Например, сервис doctrine является публичным:

1
2
// таким образом можно получить доступ только к публичным сервисам
$doctrine = $container->get('doctrine');

Но обычно, доступ к сервисам получают, используя внедрение зависимости . И в этом случае, эти сервисы не должны быть публичными.

Так что разве что вам не нужно специально получить доступ напрямую из контейнера через $container->get(), наилучшей практикой будет сделать ваши сервисы приватными. На самом деле, все сервисы приватные по умолчанию.

Вы также можете контролировать опцию public на основании каждого сервиса:

1
2
3
4
5
6
# config/services.yaml
services:
    # ...

    App\Service\Foo:
        public: true

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

Теперь, когда сервис приватный, вы не должны вызывать сервис напрямую из контейнера:

1
2
3
use AppBundle\Service\Foo;

$container->get(Foo::class);

Таким образом, сервис может быть отмечен приватным, если вы не хотите получать к нему доступ напрямую из вашего кода. Однако, если сервис был отмечен, как приватный, вы всё ещё можете создать ему псевдоним (смотрите ниже), чтобы получить доступ к этому сервису (через псевдоним).

Псевдонимы

Иногда вам может захотеться использовать сокращения для доступа к некоторым сервисам. Вы можете сделать это, предоставив сервисам псевдонимы и, более того, вы можете давать такие имена даже непубличным сервисам.

1
2
3
4
5
6
7
8
9
10
11
// src/Mail/PhpMailer.php
namespace App\Mail;

// ...
use Symfony\Component\DependencyInjection\Attribute\AsAlias;

#[AsAlias(id: 'app.mailer', public: true)]
class PhpMailer
{
    // ...
}

Это означает, что при использовании контейнера напрямую, вы можете получить доступ к сервису PhpMailer, запросив сервис app.mailer таким образом:

1
$container->get('app.mailer'); // Вернет экземпляр PhpMailer

Tip

В YAML вы также можете использовать шорткат для псевдонима сервиса:

1
2
3
4
# config/services.yaml
services:
    # ...
    app.mailer: '@App\Mail\PhpMailer'

Tip

При использовании атрибута #[AsAlias] можно не передавать аргумент id, если класс реализует только один интерфейс. MailerInterface будет псевдонимом PhpMailer:

1
2
3
4
5
6
7
8
9
10
11
12
// src/Mail/PhpMailer.php
namespace App\Mail;

// ...
use Symfony\Component\DependencyInjection\Attribute\AsAlias;
use Symfony\Component\Mailer\MailerInterface;

#[AsAlias]
class PhpMailer implements MailerInterface
{
    // ...
}

Устаревание псевдонимов сервисов

Когда вы решили объявить использование псевдонима сервиса устаревшим (потому что он устарел, или вы решили больше его не поддерживать), вы можете обозначить его определение устаревшим:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.mailer:
    alias: 'App\Mail\PhpMailer'

    # это выводит следующее общее сообщение об устаревании:
    # Начиная с acme/package 1.2: Псевдоним сервиса "app.mailer" устарел. Вы должны перестать его использовать, так как он будет удален в будущем
    deprecated:
        package: 'acme/package'
        version: '1.2'

    # вы также можете определить пользовательское сообщение об устаревании (доступен заполнитель %alias_id%)
    deprecated:
        package: 'acme/package'
        version: '1.2'
        message: 'The "%alias_id%" alias is deprecated. Do not use it anymore.'

Теперь, каждый раз, когда будет использован этот сервис, будет вызываться предупреждение об устаревании, советующее вам прекратить или изменить использование этого сервиса.

Сообщение на самом деле является шаблоном, который замещает явление замены id сервиса заполнителем %alias_id%. Вы должны иметь как минимум одно явление заполнителя %alias_id% в вашем шаблоне.

Анонимные сервисы

В некоторых случаях, вы можете захотеть предотвратить использование сервиса в качестве зависимости других сервисов. Этого можно достичь путем создания анонимного сервиса. Эти сервисы такие же, как другие обычные сервисы, но они не определяют ID и они создаются, когда используются.

Следующий пример отображает, как внедрить анонимные сервис в другой сервис:

1
2
3
4
5
6
# config/services.yaml
services:
    App\Foo:
        arguments:
            - !service
                class: App\AnonymousBar

Note

Анонимные сервисы НЕ наследуют определения, предоставленные из значений по умолчанию определенных в конфигурации. Поэтому вам нужно будет ясно отметить сервис как автомонтируемый или автоконфигурируемый, когда вы создаете анонимный сервис, к примеру: inline_service(Foo::class)->autowire()->autoconfigure().

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

1
2
3
4
# config/services.yaml
services:
    App\Foo:
        factory: [ !service { class: App\FooFactory }, 'constructFoo' ]

Устаревание сервисов

Когда вы решили объявить использование сервиса устаревшим (потому что он устарел, или вы решили больше его не поддерживать), вы можете обозначить его определение устаревшим:

1
2
3
4
5
6
# config/services.yaml
App\Service\OldService:
    deprecated:
        package: 'vendor-name/package-name'
        version: '2.8'
        message: Сервис "%service_id%" устарел, начиная с vendor-name/package-name 2.8 и будет удален в 3.0.

Теперь, каждый раз, когда сервис используется, запускается предупреждение об устаревании, советующее вам прекратить или изменить использование этого сервиса.

Сообщение на самом деле является шаблоном сообщения, которое заменяет появления заполнителя %service_id% на id сервиса. Вы должны иметь как минимум одно появление заполнителя %service_id% в вашем шаблоне.

Note

Сообщение об устаревании необязательно. Если оно не установлено, Symfony отобразит следующее сообщение по умолчанию: Сервис "%service_id%" устарел. Вам стоит перестать использовать его, так как он вскоре будет удалён..

Tip

Очень рекомендуется, чтобы вы определили ползовательское сообщение, так как сообщение по умолчанию слишком общее. Хорошее сообщение информирует о том, когда устарел данный сервис, до когда он будет поддерживаться и предлагает альтернативные сервисы для использования (если они существуют).

Для декораторов сервиса (см. Как декорировать сервисы), если определение не изменяет статус устаревания, он унаследует статус из определения, которое декорируется.