如何注入基于复杂表达式的值

3.4 版本
维护中的版本

服务容器支持一种称为“表达式”的语言,允许你将非常特殊的值注入到服务中。

例如,假设你有一个新的服务(不在这里明示),叫mailer_configuration,它有一个getMailerMethod()方法,基于某些配置来返回像一个像sendmail这样的字符串。你还记得,app.mailer服务的第一个参数就是sendmail:

1
2
3
4
5
# app/config/services.yml
services:
    app.mailer:
        class:        AppBundle\Mailer
        arguments:    [sendmail]
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 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" class="AppBundle\Mailer">
            <argument>sendmail</argument>
        </service>
    </services>
</container>
1
2
3
4
5
6
7
// app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
 
$container->setDefinition('app.mailer', new Definition(
    'AppBundle\Mailer',
    array('sendmail')
));

但是有别于在配置服务时写死,我们如何才能从新服务mailer_configurationgetMailerMethod()方法中得到这个值呢? 其中一个办法就是使用表达式:

1
2
3
4
5
# app/config/config.yml
services:
    my_mailer:
        class:        Acme\HelloBundle\Mailer
        arguments:    ["@=service('mailer_configuration').getMailerMethod()"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- app/config/config.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="my_mailer" class="Acme\HelloBundle\Mailer">
            <argument type="expression">service('mailer_configuration').getMailerMethod()</argument>
        </service>
    </services>
</container>
1
2
3
4
5
6
7
8
// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\ExpressionLanguage\Expression;
 
$container->setDefinition('my_mailer', new Definition(
    'Acme\HelloBundle\Mailer',
    array(new Expression('service("mailer_configuration").getMailerMethod()'))
));

关于更多表达式语法,参考这里The Expression Syntax

此处的上下文,你使用了两个功能:

service 返回一个指定服务(见上面代码)

parameter 返回一个参数值(用法和service类似)

你还可以使用ContainerBuilder ,通过container 变量来实现。下面是另一个例子:

1
2
3
4
services:
    my_mailer:
        class:     Acme\HelloBundle\Mailer
        arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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="my_mailer" class="Acme\HelloBundle\Mailer">
            <argument type="expression">container.hasParameter('some_param') ? parameter('some_param') : 'default_value'</argument>
        </service>
    </services>
</container>
1
2
3
4
5
6
7
8
9
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\ExpressionLanguage\Expression;
 
$container->setDefinition('my_mailer', new Definition(
    'Acme\HelloBundle\Mailer',
    array(new Expression(
        "container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"
    ))
));

表达式可以使用在服务定义中的方法参数(arguments to method call)和属性(properties)中。注:作为参数时,也可以是configurator的参数。(译注:此处高难,参考DI组件文档相关

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)