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

Как внедрять значения, основанные на сложных выражениях

Сервис-контейнер также поддерживает “выражение”, которое позволяет вам внедрять очень особенные значения в сервис.

Например, представьте, что у вас есть сервис (здесь не показан), под названием App\Mail\MailerConfiguration, который в себе имеет метод getMailerMethod(). Он возвращает строку вроде sendmail, основываясь на какой-то конфигурации.

Представьте, что вы хотите передать результат этого метода в качестве аргумента конструктора другому сервису: App\Mailer. Одним из способов сделать это - с помощью выражения:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    # config/services.yaml
    services:
        # ...
    
        App\Mail\MailerConfiguration: ~
    
        App\Mailer:
            # префикс '@=' обязателен при использовании выражений для аргументов в файлах YAML
            arguments: ['@=service("App\\Mail\\MailerConfiguration").getMailerMethod()']
            # при использовании строк с двойными кавычками, братный слэш должен быть экранирован дважды (см. https://yaml.org/spec/1.2/spec.html#id2787109)
            # аргументы: ["@=service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()"]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <!-- ... -->
    
            <service id="App\Mail\MailerConfiguration"></service>
    
            <service id="App\Mailer">
                <argument type="expression">service('App\\Mail\\MailerConfiguration').getMailerMethod()</argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Mail\MailerConfiguration;
    use App\Mailer;
    
    return function(ContainerConfigurator $configurator) {
        // ...
    
        $services->set(MailerConfiguration::class);
    
        $services->set(Mailer::class)
            // из-за экранирования, примененного PHP, вы должны добавить 4 обратных слэша для каждого изначального обратного слэша
            ->args([expr("service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()")]);
    };
    

Чтобы узнать больше о синтаксисе языка выражений, см. The Expression Syntax.

В этом контексте, у вас есть доступ к 2 функциям:

service
Возвращает данный сервис (смотрите пример выше).
parameter
Возвращает конкретное значение параметра (синтаксис такой же, как в service).

Вы также имеете доступ к Container через переменную container. Вот ещё один пример:

  • YAML
    1
    2
    3
    4
    5
    # config/services.yaml
    services:
        App\Mailer:
            # префикс '@=' обязателен при использовании выражений для аргументов в файлах YAML
            arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Mailer">
                <argument type="expression">container.hasParameter('some_param') ? parameter('some_param') : 'default_value'</argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Mailer;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(Mailer::class)
            ->args([expr("container.hasParameter('some_param') ? parameter('some_param') : 'default_value'")]);
    };
    

Выражения могут быть использованы в arguments, properties, в качестве аргументов с configurator и аргументов к calls (вызовы метода).

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