DI组件,允许你在程序中以标准化和中心化的方式来构建对象。依赖注入组件被用来创建服务容器,而这是Symfony框架的强扩展性的最大功臣。Symfony 2.7对DependencyInjection component改进了一些功能,同时也移除了一些功能。

添加了一个auto_alias compiler pass 

这个新功能的出现,是Drupal项目的需求。他们定义了一个“系列化的相关服务”,像下面这样:

1
2
3
4
5
6
lock:
    class: Drupal\Core\Lock\Lock...
mysql.lock:
    class: Drupal\Core\Lock\MysqlLock...
sqlite.lock:
    class: Drupal\Core\Lock\SqliteLock...

当网站管理员设置default_backend配置选项为mysql时,与之对应的mysql.lock服务将被自动设置一个通用的lock假名。

在Symfony 2.7中,一个全新的auto_alias compiler pass被添加,它允许定义一个“基于容器参数的值”的自动化假名。你只需给服务打一个auto_alias标签,然后定义假名格式(可以引入任何一个容器参数):

1
2
3
4
# app/config/services.yml
lock:
    tags:
        - { name: auto_alias, format: "%default_backend%.lock" }

改进的YAML格式服务定义语法 

YAML是Symfony程序的三大配置格式之一,可以用来定义服务。在Symfony 2.6和之前版本,YAML格式的复杂服务定义可能是下面样子:

1
2
3
4
5
6
7
8
9
10
# app/config/services.yml
services:
    manager:
        class:     AppBundle\Manager\UserManager
        arguments: [true]
        calls:
            - [setLogger, ["@logger"]]
            - [setClass, ["User"]]
        tags:
            -  { name: twig.extension, alias: user }

在Symfony 2.7中,配置语法被改善了,允许使用冗余的、表达力更强的服务定义(当然你也可以保持以前的配置方式,如果你喜欢的话):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# app/config/services.yml
services:
    manager:
        class: AppBundle\Manager\UserManager
        arguments:
          - true
        calls:
          - method: setLogger
            arguments:
              - "@logger"
          - method: setClass
            arguments:
              - User
        tags:
          - name: manager
            alias: user

弱化了的合成服务 

在Symfony服务容器中,一个服务不能依赖“来自窄scope”的服务。例如,你创建了一个服务,并尝试向它注入request服务,你会收到ScopeWideningInjectionException异常:

从Symfony 2.3起引入了一个合成服务(synchronized services)的概念用于解决此问题。这也是为何request服务被定义为synchronized的原因:

1
2
3
4
5
services:
    request:
        scope: request
        synchronized: true
        # ...

然后你在服务中可以使用setter注入,来安全地使用这种类型的“合成服务”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace AppBundle\Mail;
 
use Symfony\Component\HttpFoundation\Request;
 
class Mailer
{
    protected $request;
 
    public function setRequest(Request $request = null)
    {
        $this->request = $request;
    }
 
    // ...
}
1
2
3
4
5
6
# app/config/services.yml
services:
    mailer:
        class: AppBundle\Mail\Mailer
        calls:
            - [setRequest, ["@?request"]]

但是,真正的问题在于,request请求并非服务,而只是一个值对象。在Symfony3.0中,我们将从容器中删除request服务,来彻底解决此类(注入)问题。

另外,我们也deprecated synchronized services in Symfony 2.7,因为这个功能对某些不需要它的需求来说太过复杂,可以说是一种错误的解决问题方式。如果你的服务需要request服务,请使用request_stack服务来替代。