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

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

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

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

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

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

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

  • YAML
    1
    2
    3
    4
    5
    services:
        # ...
    
        AppBundle\Service\Foo:
            public: false
    
  • XML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?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="AppBundle\Service\Foo" public="false" />
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    use AppBundle\Service\Foo;
    
    $container->register(Foo::class)
        ->setPublic(false);
    

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

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

1
2
3
use AppBundle\Service\Foo;

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

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

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

Note

По умолчанию сервисы являются публичными, но считается хорошей практикой помечать максимально возможное количество сервисов приватными.

Альтернативное именование

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

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    services:
        # ...
        AppBundle\Mail\PhpMailer:
            public: false
    
        app.mailer:
            alias: AppBundle\Mail\PhpMailer
            public: true
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <?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 class="AppBundle\Mail\PhpMailer" public="false" />
    
            <service id="app.mailer" alias="AppBundle\Mail\PhpMailer" />
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    use AppBundle\Mail\PhpMailer;
    
    $container->register(PhpMailer::class)
        ->setPublic(false);
    
    $container->setAlias('app.mailer', PhpMailer::class);
    

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

1
$container->get('app.mailer'); // Would return a PhpMailer instance

Tip

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

1
2
3
services:
    # ...
    app.mailer: '@app.phpmailer'

Осуждение сервисов

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

  • YAML
    1
    2
    AppBundle\Service\OldService:
        deprecated: Сервис "%service_id%" был осуждён с версии 2.8 и будет удалён в версии 3.0.
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    <?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="AppBundle\Service\OldService">
                <deprecated>Сервис "%service_id%" был осуждён с версии 2.8 и будет удалён в версии 3.0</deprecated>
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    use AppBundle\Service\OldService;
    
    $container
        ->register(OldService::class)
        ->setDeprecated(
            true,
            'Сервис "%service_id%" был осуждён с версии 2.8 и будет удалён в версии 3.0'
        )
    ;
    

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

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

Note

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

Tip

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

Для декораторов сервиса (см. How to Decorate Services), если определение не изменяет статус осуждение, он унаследует статус из определения, которое декорируется.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.