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
服务来替代。