自动定义服务依赖关系(自动装配)
编辑本页警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 3.3,现已不再维护。
读本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。
自动定义服务依赖关系(自动装配)
自动装配允许您以最小的配置管理容器中的服务。它读取构造函数(或其他方法)上的类型提示,并自动将正确的服务传递给每个方法。ob娱乐下载Symfony的自动装配被设计为可预测的:如果不完全清楚应该传递哪个依赖项,您将看到一个可操作的异常。
提示
由于Symfony的ob娱乐下载编译容器,使用自动装配没有运行时开销。
一个自动装配的例子
想象一下,您正在构建一个API,用于在Twitter提要上发布状态ROT13...一个有趣的编码器,将所有字符在字母表中向前移动13个字母。
首先创建一个ROT13转换器类:
1 2 3 4 5 6 7 8 9
名称空间AppBundle\跑龙套;类Rot13Transformer{公共函数变换($价值){返回函数$价值);}}
现在使用这个转换器的Twitter客户端:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
名称空间AppBundle\服务;使用AppBundle\跑龙套\Rot13Transformer;类TwitterClient{私人$变压器;公共函数__construct(Rot13Transformer$变压器){$这->变压器=$变压器;}公共函数推特($用户,$关键,$状态){$transformedStatus=$这->变压器->变换($状态);/ /……连接到Twitter并发送编码状态}}
如果你在用默认的服务。yml配置,两个类都自动注册为服务,并配置为自动连接.这意味着你可以立即使用它们任何配置。
但是,为了更好地理解自动装配,下面的示例显式地配置这两个服务。此外,为了保持简单,请进行配置TwitterClient
成为一名公共服务:
- YAML
- XML
- PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15
服务:_defaults:自动装配:真正的可以使用autoconfigure:真正的公众:假#……AppBundle \服务\ TwitterClient:#由于_defaults的存在而显得多余,但是value在每个服务上都是可重写的自动装配:真正的# not required,将在我们的例子中有所帮助公众:真正的AppBundle \ Util \ Rot13Transformer:自动装配:真正的
现在,你可以使用TwitterClient
服务立即在控制器中:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
名称空间AppBundle\控制器;使用AppBundle\服务\TwitterClient;使用Sensio赞助\包\FrameworkExtraBundle\配置\路线;使用ob娱乐下载\包\FrameworkBundle\控制器\控制器;类DefaultController扩展控制器{/ * * *@Route(“/推”)* /公共函数tweetAction(){//从POST的数据中获取$user, $key, $status$twitterClient=$这->容器->get (TwitterClient::类);$twitterClient->推特($用户,$关键,$状态);/ /……}}
这是自动工作!容器知道传递Rot13Transformer
类时,将服务作为第一个参数TwitterClient
服务。
自动装配逻辑解释
自动装配工作通过读取Rot13Transformer
type-hint在TwitterClient
:
12 3 4 5 6 7 8 9 10 11 12
/ /……使用AppBundle\跑龙套\Rot13Transformer;类TwitterClient{/ /……公共函数__construct(Rot13Transformer$变压器){$这->变压器=$变压器;}}
自动装配系统查找id与类型提示完全匹配的服务:所以AppBundle \ Util \ Rot13Transformer
.在这种情况下,它是存在的!当您配置Rot13Transformer
服务,您使用它的全限定类名作为它的id。自动装配并不神奇:它只是寻找id与类型提示匹配的服务。如果你自动加载服务,每个服务的id是它的类名。这是控制自动装配的主要方法。
如果有的话不服务id与类型完全匹配,则:
- 如果有0类型的容器中的服务,则:
- 如果类型是具体类,则在容器中自动注册一个新的、私有的、自动连接的服务,并将其用于参数。
- 如果有的话1服务,则:
- (已弃用)此服务用于参数。在Syob娱乐下载mfony 4.0中,这将被删除。正确的解决方案是创建一个别名从类型到服务id,以便正常的自动装配工作。
- 如果有2个或更多类型的容器中的服务,则:
- 抛出一个明确异常。你需要选择创建?应该使用哪个服务别名或显式配置参数.
自动装配是一种自动化配置的好方法,Symfony试图做到这一点ob娱乐下载可预测的而且越清楚越好。
使用别名来启用自动装配
配置自动装配的主要方法是创建一个id与类完全匹配的服务。在前面的例子中,服务的id是AppBundle \ Util \ Rot13Transformer
,它允许我们自动装配该类型。
也可以使用别名.假设由于某种原因,服务的id改为app.rot13.transformer
.在这种情况下,任何带有类名(AppBundle \ Util \ Rot13Transformer
)不能再自动连接(实际上,它将工作现在,但不是在Symfony 4.0ob娱乐下载).
没问题!你可以解决这个问题创建通过添加服务别名来匹配类的服务:
- YAML
- XML
- PHP
12 3 4 5 6 7 8 9 10 11 12
服务:#……# id不是一个类,所以它不会被用于自动装配app.rot13.transformer:类:AppBundle \ Util \ Rot13Transformer#……#但这修复它!#应用程序。rot13。变压器`` service will be injected when# an ' AppBundle\Util\Rot13Transformer ' '类型提示被检测到AppBundle \ Util \ Rot13Transformer:“@app.rot13.transformer”
这将创建一个服务“别名”,其id为AppBundle \ Util \ Rot13Transformer
.由于这一点,autotowiring看到这一点,并使用它每当Rot13Transformer
类是类型提示的。
提示
核心包使用别名来允许自动连接服务。例如,MonologBundle创建了一个id为的服务日志记录器
.但它也添加了一个别名:Psr \ \ LoggerInterface日志
这就指向了日志记录器
服务。这就是为什么参数要用Psr \ \ LoggerInterface日志
可以自动连接。
使用接口
你可能还会发现自己使用类型提示抽象(例如接口)而不是具体的类,因为它可以很容易地用其他对象替换你的依赖项。
为了遵循此最佳实践,假设您决定创建一个TransformerInterface
:
1 2 3 4 5 6
名称空间AppBundle\跑龙套;接口TransformerInterface{公共函数变换($价值);}
然后更新Rot13Transformer
要实现它:
1 2 3 4 5
/ /……类Rot13Transformer实现了TransformerInterface{/ /……}
现在你有了一个接口,你应该使用这个作为你的输入提示:
1 2 3 4 5 6 7 8 9
类TwitterClient{公共函数__construct(TransformerInterface$变压器){/ /……}/ /……}
但是现在,type-hint (AppBundle \ Util \ TransformerInterface
)不再匹配服务的id (AppBundle \ Util \ Rot13Transformer
).这意味着参数不能再自动连接(实际上,它将工作现在,但不是在Symfony 4.0ob娱乐下载).
要解决这个问题,请添加别名:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8
服务:#……AppBundle \ Util \ Rot13Transformer:~# AppBundle\Util\Rot13Transformer ' '服务将被注入# an ' AppBundle\Util\TransformerInterface ' '类型提示被检测到AppBundle \ Util \ TransformerInterface:“@AppBundle \ Util \ Rot13Transformer”
多亏了AppBundle \ Util \ TransformerInterface
别名,自动装配子系统知道AppBundle \ Util \ Rot13Transformer
服务应该在处理TransformerInterface
.
处理相同类型的多个实现
假设您创建了第二个类-UppercaseTransformer
实现TransformerInterface
:
1 2 3 4 5 6 7 8 9
名称空间AppBundle\跑龙套;类UppercaseTransformer实现了TransformerInterface{公共函数变换($价值){返回strtoupper ($价值);}}
如果您将其注册为服务,您现在就拥有了两个实现AppBundle \ Util \ TransformerInterface
类型。ob娱乐下载Symfony不知道应该使用哪一个来自动装配,因此您需要通过创建从类型到正确服务id的别名来选择一个自动定义服务依赖关系(自动装配)).
如果你愿意Rot13Transformer
要成为用于自动装配的服务,请创建别名:
- YAML
- XML
- PHP
12 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 ' '服务将被注入检测到# a ' ' AppBundle\Util\TransformerInterface ' '类型提示AppBundle \ Util \ TransformerInterface:“@AppBundle \ Util \ Rot13Transformer”AppBundle \服务\ TwitterClient:# the Rot13Transformer将作为$transformer参数传递自动装配:真正的#如果你想选择非默认的服务,手动连接它#参数:# $transformer: '@AppBundle\Util\UppercaseTransformer'#……
多亏了AppBundle \ Util \ TransformerInterface
别名,此接口中任何类型提示的参数都将被传递AppBundle \ Util \ Rot13Transformer
服务。但是,您也可以手动连接其他服务,在arguments键下指定参数。
3.3
使用FQCN别名来修复自动装配歧义是在Symfony 3.3中引入的。ob娱乐下载在3.3版本之前,您需要使用autowiring_types
关键。
修复不可自动连接的参数
自动装配仅在参数为对象.但是如果你有一个标量参数(例如一个字符串),这不能自动连接:Symfony将抛出一个明确的异常。ob娱乐下载
你可以解决这个问题手动连接有问题的参数.你把困难的论点连接起来,Symfony会处理剩下的。ob娱乐下载
自动装配其他方法(例如setter)
当为服务启用自动装配时,可以也配置容器,使其在实例化类时调用类上的方法。例如,假设您想要注入日志记录器
服务,并决定使用setter-injection:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
名称空间AppBundle\跑龙套;类Rot13Transformer{私人$日志记录器;/ * * *@ required* /公共函数setLogger(LoggerInterface$日志记录器){$这->记录器=$日志记录器;}公共函数变换($价值){$这->日志记录器->信息(“改变”.$价值);/ /……}}
Autowiring将自动调用任何方法。@ required
注释,自动装配每个参数。如果您需要手动将一些参数连接到方法,您总是可以显式地配置方法调用.
自动装配控制器动作方法
如果您正在使用Symfony框架,您还可ob娱乐下载以将参数自动装配到控制器动作方法。这是自动装配的一个特殊情况,它的存在是为了方便。看到控制器欲知详情。
性能的影响
多亏了Symfonyob娱乐下载的编译容器,才有了没有使用自动装配的性能损失。但是,有一个小的性能损失dev
环境,因为在修改类时可能更频繁地重新构建容器。如果重新构建容器很慢(可能在非常大的项目上),您可能无法使用自动装配。
公共和可重用的捆绑包
公共包应该显式地配置它们的服务,而不依赖于自动装配。