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