Как сделать аргументы/ссылки сервисов необязательными

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

Установка отсутствующих зависимостей как null

Вы можете использовать стратегию null, чтобы ясно устаовить аргумент как null, если сервис не существует:

  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    <!-- app/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
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <!-- ... -->
    
            <service id="AppBundle\Newsletter\NewsletterManager">
                <argument type="service" id="logger" on-invalid="null" />
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    // app/config/services.php
    use AppBundle\Newsletter\NewsletterManager;
    use Symfony\Component\DependencyInjection\Reference;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    // ...
    
    $container->register(NewsletterManager::class)
        ->addArgument(new Reference(
            'logger',
            ContainerInterface::NULL_ON_INVALID_REFERENCE
        ));
    

Note

Стратегия "null" на сегодня не поддерживается драйвером YAML.

Игнорирование отсутствующих зависимостей

Поведение игнорирования отсутствующих зависимостей такое же, как и поведение "null", кроме случаев использования внутри вызова метода, когда сам метод вызова будет удалён.

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

  • YAML
    1
    2
    3
    4
    5
    6
    # app/config/services.yml
    services:
        app.newsletter_manager:
            class: AppBundle\Newsletter\NewsletterManager
            calls:
                - [setLogger, ['@?logger']]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- app/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
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="app.mailer">
            <!-- ... -->
            </service>
    
            <service id="AppBundle\Newsletter\NewsletterManager">
                <call method="setLogger">
                    <argument type="service" id="logger" on-invalid="ignore"/>
                </call>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // app/config/services.php
    use AppBundle\Newsletter\NewsletterManager;
    use Symfony\Component\DependencyInjection\Reference;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    $container
        ->register(NewsletterManager::class)
        ->addMethodCall('setLogger', array(
            new Reference(
                'logger',
                ContainerInterface::IGNORE_ON_INVALID_REFERENCE
            ),
        ))
    ;
    

Note

Если аргумент вызова метода является коллекцией аргументов, и отсутствуют какие- либо из них, то эти элеметыбудут удалены, но метод вызова всё равно будет выполнен с оставшимися элементами коллекции.

В YAML, специальный синтаксис @? говорит сервис-контейнеру, что зависимость является необязательной. Конечно же, NewsletterManager тоже должен быть переписан, путём добавления метода setLogger():

1
2
3
4
public function setLogger(LoggerInterface $logger)
{
    // ...
}

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