自动定义服务依赖关系(自动装配)
编辑该页面警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 3.4,不再维护。
读这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。
自动定义服务依赖关系(自动装配)
自动装配允许您管理服务的容器以最小的配置。它读取类型提示你的构造函数(或其他方法),并自动为每个方法传递正确的服务。欧宝娱乐app下载地址Symfony的自动装配设计是可以预见的:如果不是很清楚哪些依赖应该通过,您将看到一个可操作的例外。
提示
由于Symfony的欧宝娱乐app下载地址编译后的容器,没有使用自动装配的运行时开销。
一个自动装配的例子
想象一下你正在构建一个API在Twitter发布状态,混淆ROT13一个有趣的编码器,转移所有字符13个字母在字母表。
首先创建一个ROT13变压器类:
1 2 3 4 5 6 7 8 9
名称空间AppBundle\跑龙套;类Rot13Transformer{公共函数变换(美元价值){返回函数美元价值);}}
现在Twitter客户端使用这个变压器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
名称空间AppBundle\服务;使用AppBundle\跑龙套\Rot13Transformer;类TwitterClient{私人美元变压器;公共函数__construct(Rot13Transformer美元变压器){美元这- >变压器=美元变压器;}公共函数推特(美元用户,美元关键,美元状态){美元transformedStatus=美元这- >变压器- >变换(美元状态);/ /……连接到Twitter和发送编码状态}}
如果你使用默认的服务。yml配置,两类自动注册为服务和配置为autowired的。这意味着您可以立即使用它们任何配置。
然而,为了更好地理解自动装配,下面的例子明确配置两个服务:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8 9 10 11 12 13
服务:_defaults:自动装配:真正的可以使用autoconfigure:真正的公众:假#……AppBundle \服务\ TwitterClient:#由于_defaults冗余,但价值是重写的每个服务自动装配:真正的AppBundle \ Util \ Rot13Transformer:自动装配:真正的
1 2 3 4 5 6 7 8 9 10 11 12 13 14
< ?xml version = " 1.0 " encoding = " utf - 8 " ? ><容器xmlns=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services //www.oldmanjams.com/schema/dic/services/services-1.0.xsd”><服务><违约自动装配=“真正的”可以使用autoconfigure=“真正的”公共=“假”/ >< !——……- - ><服务id=“AppBundle \服务\ TwitterClient”自动装配=“真正的”/ ><服务id=“AppBundle \ Util \ Rot13Transformer”自动装配=“真正的”/ >< /服务>< /容器>
1 2 3 4 5 6 7 8 9 10 11
使用AppBundle\服务\TwitterClient;使用AppBundle\跑龙套\Rot13Transformer;/ /……/ /自动装配方法是新的在Symfony 3.3欧宝娱乐app下载地址/ /在早期版本中,使用注册(),然后调用setAutowired(真正的)美元容器- >自动装配(TwitterClient::类);美元容器- >自动装配(Rot13Transformer::类)- >setPublic (假);
现在,您可以使用TwitterClient
服务立即控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
名称空间AppBundle\控制器;使用AppBundle\服务\TwitterClient;使用欧宝娱乐app下载地址\包\FrameworkBundle\控制器\控制器;使用欧宝娱乐app下载地址\组件\路由\注释\路线;类DefaultController扩展控制器{/ * * *@Route(“/推”,方法= {“POST”}) * /公共函数tweetAction(TwitterClient美元twitterClient){/ /获取用户,美元,美元地位的“POST”数据美元twitterClient- >推特(美元用户,美元关键,美元状态);/ /……}}
这是自动!容器知道通过Rot13Transformer
当创建服务作为第一个参数TwitterClient
服务。
自动装配逻辑解释
自动装配是通过读取Rot13Transformer
type-hint在TwitterClient
:
1 2 3 4 5 6 7 8 9 10 11 12
/ /……使用AppBundle\跑龙套\Rot13Transformer;类TwitterClient{/ /……公共函数__construct(Rot13Transformer美元变压器){美元这- >变压器=美元变压器;}}
自动装配系统寻找一个服务其id type-hint完全匹配:所以AppBundle \ Util \ Rot13Transformer
。在这种情况下,存在!当您配置Rot13Transformer
服务,您使用它的完全限定类名作为其id。自动装配并不是魔法:它看起来的服务id匹配type-hint。如果你负载自动服务,每个服务的id是它的类名。这是控制自动装配的主要方式。
如果有不一个服务id完全匹配的类型,然后:
- 如果有0服务容器的类型,那么:
- 如果类型是一个具体的类,那么一个新的私人,auto-registered autowired的服务使用的容器和论点。
- 如果有确切1服务容器的类型,然后:
- (弃用)该服务用于参数。在Sy欧宝娱乐app下载地址mfony 4.0中,这将被删除。适当的解决方案是创建一个别名从类型服务id,以便正常的自动装配工作。
- 如果有2个或更多服务容器的类型,那么:
- 一个明确的异常。你需要选择应该使用哪个服务创建一个别名或配置参数显式地。
自动装配是一个伟大的方式来自动配置和Symfony试图一样欧宝娱乐app下载地址可预测的尽可能的和明确的。
使用别名来实现自动装配
配置自动装配的主要方式是创建一个id完全匹配它的类的服务。在前面的示例中,服务的idAppBundle \ Util \ Rot13Transformer
自动,它允许我们自动装配这种类型。
这也可以使用一个完成别名。假设由于某种原因,服务的idapp.rot13.transformer
。在这种情况下,任何参数type-hinted类名(AppBundle \ Util \ Rot13Transformer
)可以不再autowired的(实际上,它现在工作,但不是在Symfony 4.0吗欧宝娱乐app下载地址)。
没问题!为了解决这个问题,你可以创建服务的id匹配的类添加一个服务别名:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8 9 10 11 12
服务:#……# id不是一个类,所以它不会被用于自动装配app.rot13.transformer:类:AppBundle \ Util \ Rot13Transformer#……#但这修复它!#“app.rot13。变压器`` service will be injected when< /span>#一个‘AppBundle \ Util \ Rot13Transformer“type-hint检测AppBundle \ Util \ Rot13Transformer:“@app.rot13.transformer”
1 2 3 4 5 6 7 8 9 10 11 12
< ?xml version = " 1.0 " encoding = " utf - 8 " ? ><容器xmlns=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services //www.oldmanjams.com/schema/dic/services/services-1.0.xsd”><服务>< !——……- - ><服务id=“app.rot13.transformer”类=“AppBundle \ Util \ Rot13Transformer”自动装配=“真正的”/ ><服务id=“AppBundle \ Util \ Rot13Transformer”别名=“app.rot13.transformer”/ >< /服务>< /容器>
1 2 3 4 5 6 7
使用AppBundle\跑龙套\Rot13Transformer;/ /……美元容器- >自动装配(“app.rot13.transformer”,Rot13Transformer::类)- >setPublic (假);美元容器- >setAlias (Rot13Transformer::类,“app.rot13.transformer”);
这将创建一个服务“别名”,其idAppBundle \ Util \ Rot13Transformer
。谢谢,自动装配认为这和使用它Rot13Transformer
类是type-hinted。
提示
所使用的别名是autowired的核心包允许服务。例如,MonologBundle创建一个服务的id日志记录器
。但它也添加别名:Psr \ \ LoggerInterface日志
指向日志记录器
服务。这就是为什么参数type-hintedPsr \ \ LoggerInterface日志
可以autowired的。
使用接口
你也可能发现自己类型提示抽象(如接口)而不是具体类,因为它取代你的依赖与其他对象。
遵循这些最佳实践,假设你决定创建一个TransformerInterface
:
1 2 3 4 5 6
名称空间AppBundle\跑龙套;接口TransformerInterface{公共函数变换(美元价值);}
然后,你更新Rot13Transformer
实现它:
1 2 3 4 5
/ /……类Rot13Transformer实现了TransformerInterface{/ /……}
现在你有一个接口,您应该使用这个作为type-hint:
1 2 3 4 5 6 7 8 9
类TwitterClient{公共函数__construct(TransformerInterface美元变压器){/ /……}/ /……}
但是现在,type-hint (AppBundle \ Util \ TransformerInterface
)不再匹配的id服务(AppBundle \ Util \ Rot13Transformer
)。这意味着这个论点可以不再autowired的(实际上,它现在工作,但不是在Symfony 4.0吗欧宝娱乐app下载地址)。
为了解决这个问题,添加一个别名:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8
服务:#……AppBundle \ Util \ Rot13Transformer:~#“AppBundle \ Util \ Rot13Transformer“服务时将被注入#一个‘AppBundle \ Util \ TransformerInterface“type-hint检测AppBundle \ Util \ TransformerInterface:“@AppBundle \ Util \ Rot13Transformer”
1 2 3 4 5 6 7 8 9 10 11 12
< ?xml version = " 1.0 " encoding = " utf - 8 " ? ><容器xmlns=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services //www.oldmanjams.com/schema/dic/services/services-1.0.xsd”><服务>< !——……- - ><服务id=“AppBundle \ Util \ Rot13Transformer”/ ><服务id=“AppBundle \ Util \ TransformerInterface”别名=“AppBundle \ Util \ Rot13Transformer”/ >< /服务>< /容器>
1 2 3 4 5 6
使用AppBundle\跑龙套\Rot13Transformer;使用AppBundle\跑龙套\TransformerInterface;/ /……美元容器- >自动装配(Rot13Transformer::类);美元容器- >setAlias (TransformerInterface::类,Rot13Transformer::类);
多亏了AppBundle \ Util \ TransformerInterface
别名,自动装配子系统知道AppBundle \ Util \ Rot13Transformer
服务应该被注入在处理TransformerInterface
。
提示
当使用一个服务定义原型发现,如果只有一个服务实现一个接口,该接口也同时发现,配置别名不是强制性的,Symfony会自动创建一个。欧宝娱乐app下载地址
处理多个相同类型的实现
假设您创建第二个类-UppercaseTransformer
实现TransformerInterface
:
1 2 3 4 5 6 7 8 9
名称空间AppBundle\跑龙套;类UppercaseTransformer实现了TransformerInterface{公共函数变换(美元价值){返回strtoupper (美元价值);}}
如果你注册这个服务,你现在有了两个服务实现AppBundle \ Util \ TransformerInterface
类型。自动装配子系统不能决定使用哪一个。记住,自动装配不是魔法;它看起来的一个服务id匹配type-hint。所以你需要选择一个类型的通过创建一个别名(见正确的服务id自动定义服务依赖关系(自动装配))。
如果你想要Rot13Transformer
用于自动装配的服务,创建别名:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
服务:#……AppBundle \ Util \ Rot13Transformer:~AppBundle \ Util \ UppercaseTransformer:~#“AppBundle \ Util \ Rot13Transformer“服务时将被注入#一个‘AppBundle \ Util \ TransformerInterface“type-hint检测AppBundle \ Util \ TransformerInterface:“@AppBundle \ Util \ Rot13Transformer”AppBundle \服务\ TwitterClient:# Rot13Transformer将作为美元的变压器参数传递自动装配:真正的#如果你想选择非默认服务,手动线#参数:# $变压器:“@AppBundle \ Util \ UppercaseTransformer”#……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
< ?xml version = " 1.0 " encoding = " utf - 8 " ? ><容器xmlns=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services”xmlns: xsi=“http://www.w3.org/2001/XMLSchema-instance”xsi: schemaLocation=“http://欧宝娱乐app下载地址www.oldmanjams.com/schema/dic/services //www.oldmanjams.com/schema/dic/services/services-1.0.xsd”><服务>< !——……- - ><服务id=“AppBundle \ Util \ Rot13Transformer”/ ><服务id=“AppBundle \ Util \ UppercaseTransformer”/ ><服务id=“AppBundle \ Util \ TransformerInterface”别名=“AppBundle \ Util \ Rot13Transformer”/ ><服务id=“AppBundle \服务\ TwitterClient”自动装配=“真正的”>< !——<参数键= " $变压器”类型=“服务”id = " AppBundle \ Util \ UppercaseTransformer " / > - - >< /服务>< /服务>< /容器>
1 2 3 4 5 6 7 8 9 10 11 12
使用AppBundle\服务\TwitterClient;使用AppBundle\跑龙套\Rot13Transformer;使用AppBundle\跑龙套\TransformerInterface;使用AppBundle\跑龙套\UppercaseTransformer;/ /……美元容器- >自动装配(Rot13Transformer::类);美元容器- >自动装配(UppercaseTransformer::类);美元容器- >setAlias (TransformerInterface::类,Rot13Transformer::类);美元容器- >自动装配(TwitterClient::类)/ / - > setArgument(美元变压器,新的参考(UppercaseTransformer::类));
多亏了AppBundle \ Util \ TransformerInterface
别名,任何争论type-hinted与此接口将被通过了AppBundle \ Util \ Rot13Transformer
服务。但是,你也可以手动线其他服务通过指定参数下的参数键。
3.3
使用FQCN别名解决自动装配歧义是在Symfony 3.3中引入的。欧宝娱乐app下载地址在版本3.3之前,您需要使用autowiring_types
关键。
修复Non-Autowireable参数
是一个自动装配只能当你的论点对象。但是如果你有一个标量参数(如字符串),这不能autowired: Symfony将抛出一个清晰异常。欧宝娱乐app下载地址
为了解决这个问题,你可以手动线有问题的争论。你线困难的争论,Symfony照顾休息。欧宝娱乐app下载地址
自动装配其他方法(例如setter)
当启用了自动装配的服务时,你可以也配置容器调用在你的类的实例化方法。例如,假设您想注入日志记录器
服务,并决定使用setter注入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
名称空间AppBundle\跑龙套;类Rot13Transformer{私人美元日志记录器;/ * * *@ required* /公共函数setLogger(LoggerInterface美元日志记录器){美元这- >记录器=美元日志记录器;}公共函数变换(美元价值){美元这- >日志记录器- >信息(“改变”。美元价值);/ /……}}
自动装配会自动调用任何方法与@ required
每个参数注释上面,自动装配。如果你需要手动线的一些参数的方法,你可以明确配置方法调用。
自动装配控制器动作方法
如果你使用Symfony框架,你还可以自欧宝娱乐app下载地址动装配参数控制器动作的方法。这是自动装配的特殊情况,为了方便存在。看到控制器为更多的细节。
性能的影响
由于Symfony的欧宝娱乐app下载地址容器,编译没有使用自动装配的性能损失。然而,有一个小的性能损失dev
环境,尽可能经常容器可能重建修改类。如果重建你的容器是缓慢(可能非常大的项目),你可能无法使用自动装配。
公众和可重用的包
公共bundle应该显式配置其服务,而不是依靠自动装配。自动装配取决于容器和包中可用的服务无法控制应用程序的服务容器中。你可以使用自动装配,以构建可重用的包在你的公司,你有完全控制所有的代码。