自动定义服务依赖关系(自动装配)

编辑本页

警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 5.2,现已不再维护。

本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

自动定义服务依赖关系(自动装配)

自动装配允许您以最小的配置管理容器中的服务。它读取构造函数(或其他方法)上的类型提示,并自动将正确的服务传递给每个方法。欧宝娱乐app下载地址Symfony的自动装配被设计为可预测的:如果不完全清楚应该传递哪个依赖项,您将看到一个可操作的异常。

提示

由于Symfony的欧宝娱乐app下载地址编译容器,使用自动装配没有运行时开销。

一个自动装配的例子

想象一下,您正在构建一个API,用于在Twitter提要上发布状态ROT13这是一个有趣的编码器,可以将所有字符向前移动13个字母。

首先创建一个ROT13转换器类:

1 2 3 4 5 6 7 8 9 10
/ / src / Util / Rot13Transformer.php名称空间应用程序跑龙套Rot13Transformer公共函数变换(字符串价值字符串返回函数价值);}}

现在使用这个转换器的Twitter客户端:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22
/ / src /服务/ TwitterClient.php名称空间应用程序服务使用应用程序跑龙套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 15 16 17 18 19 20 21 22 23
/ / src /控制器/ DefaultController.php名称空间应用程序控制器使用应用程序服务TwitterClient使用欧宝娱乐app下载地址FrameworkBundle控制器AbstractController使用欧宝娱乐app下载地址组件HttpFoundation请求使用欧宝娱乐app下载地址组件HttpFoundation响应使用欧宝娱乐app下载地址组件路由注释路线DefaultController扩展AbstractController/ * * *@Route("/tweet", methods={"POST"}) */公共函数推特(TwitterClienttwitterClient,请求请求响应//从POST的数据中获取$user, $key, $statustwitterClient->推特(用户关键状态);/ /……}}

这是自动工作!容器知道传递Rot13Transformer类时,将服务作为第一个参数TwitterClient服务。

自动装配逻辑解释

自动装配工作通过读取Rot13Transformertype-hintTwitterClient

12 3 4 5 6 7 8 9 10 11 12 13 14 15
/ / src /服务/ TwitterClient.php名称空间应用程序服务/ /……使用应用程序跑龙套Rot13TransformerTwitterClient/ /……公共函数__construct(Rot13Transformer变压器->变压器=变压器;}}

自动装配系统查找id与类型提示完全匹配的服务:所以App \ Util \ Rot13Transformer.在这种情况下,它是存在的!当您配置Rot13Transformer服务,您使用它的全限定类名作为它的id。自动装配并不是魔术:它会寻找id与类型提示匹配的服务。如果你自动加载服务,每个服务的id是它的类名。

如果有的话如果服务id与类型完全匹配,则将抛出一个明确异常。

自动装配是一种自动化配置的好方法,Symfony试图做到这一点欧宝娱乐app下载地址可预测的而且越清楚越好。

使用别名来启用自动装配

配置自动装配的主要方法是创建一个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 7
/ / src / Util / TransformerInterface.php名称空间应用程序跑龙套接口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将自动创建一个。欧宝娱乐app下载地址

处理相同类型的多个实现

假设您创建了第二个类-UppercaseTransformer实现TransformerInterface

1 2 3 4 5 6 7 8 9 10
/ / src / Util / UppercaseTransformer.php名称空间应用程序跑龙套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 21
/ / src /服务/ MastodonClient.php名称空间应用程序服务使用应用程序跑龙套TransformerInterfaceMastodonClient私人变压器公共函数__construct(TransformerInterfaceshoutyTransformer->变压器=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将抛出一个明确的异常。欧宝娱乐app下载地址

你可以解决这个问题手动连接有问题的参数.你把困难的论点连接起来,Symfony会处理剩下的。欧宝娱乐app下载地址

自动装配其他方法(例如setter和公共类型化属性)

当为服务启用自动装配时,可以配置容器,使其在实例化类时调用类上的方法。例如,假设您想要注入日志记录器服务,并决定使用setter-injection:

  • 注释
  • 属性
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
/ / src / Util / Rot13Transformer.php名称空间应用程序跑龙套Rot13Transformer私人日志记录器/ * * *@ required* /公共函数setLogger(LoggerInterface日志记录器无效->记录器=日志记录器;}公共函数变换价值字符串->日志记录器->信息(“改变”价值);/ /……}}

Autowiring将自动调用任何方法。#[要求]属性,自动装配每个参数。如果您需要手动将一些参数连接到方法,您总是可以显式地配置方法调用

如果您的PHP版本不支持属性(它们是在PHP 8中引入的),则可以使用@ required注释。

5.2

#[要求]属性是在Symfony 5.2中引入的。欧宝娱乐app下载地址

尽管属性注入有一些缺点,自动装配#[要求]@ required也可以应用于公共类型属性:

  • 注释
  • 属性
12 3 4 5 6 7 8 9 10 11 12 13
名称空间应用程序跑龙套Rot13Transformer/**@ required* /公共LoggerInterface日志记录器公共函数变换价值->日志记录器->信息(“改变”价值);/ /……}}

5.1

公共类型属性自动装配是在Symfony 5.1中引入的。欧宝娱乐app下载地址

自动装配控制器动作方法

如果您正在使用Symfony框架,您还可欧宝娱乐app下载地址以将参数自动装配到控制器动作方法。这是自动装配的一个特殊情况,它的存在是为了方便。看到控制器欲知详情。

性能的影响

多亏了Symfony欧宝娱乐app下载地址的编译容器,才有了没有使用自动装配的性能损失。但是,有一个小的性能损失dev环境,因为在修改类时可能更频繁地重新构建容器。如果重新构建容器很慢(可能在非常大的项目上),您可能无法使用自动装配。

公共和可重用的捆绑包

公共包应该显式地配置它们的服务,而不依赖于自动装配。自动装配依赖于容器中可用的服务,而捆绑包无法控制包含它们的应用程序的服务容器。您可以在公司内部构建可重用包时使用自动装配,因为您可以完全控制所有代码。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。