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

编辑该页面

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

自动装配允许您管理服务的容器以最小的配置。它读取类型提示你的构造函数(或其他方法),并自动为每个方法传递正确的服务。ob娱乐下载Symfony的自动装配设计是可以预见的:如果不是很清楚哪些依赖应该通过,您将看到一个可操作的例外。

提示

由于Symfony的ob娱乐下载编译后的容器,没有使用自动装配的运行时开销。

一个自动装配的例子

想象一下你正在构建一个API在Twitter发布状态,混淆ROT13一个有趣的编码器,转移所有字符13个字母在字母表。

首先创建一个ROT13变压器类:

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

现在Twitter客户端使用这个变压器:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/ / src /服务/ TwitterClient.php名称空间应用程序\服务;使用应用程序\跑龙套\Rot13Transformer;/ /……TwitterClient{私人美元变压器;公共函数__construct(Rot13Transformer美元变压器){美元- >变压器=美元变压器;}公共函数推特(用户美元用户、字符串美元关键、字符串美元状态):无效{美元transformedStatus=美元- >变压器- >变换(美元状态);/ /……连接到Twitter和发送编码状态}}

如果你使用默认的服务。yaml的配置,两类自动注册为服务和配置为autowired的。这意味着您可以立即使用它们任何配置。

然而,为了更好地理解自动装配,下面的例子明确配置两个服务:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13
#配置/ services.yaml服务:_defaults:自动装配:真正的可以使用autoconfigure:真正的#……应用程序服务\ \ TwitterClient:#由于_defaults冗余,但价值是重写的每个服务自动装配:真正的App \ Util \ Rot13Transformer:自动装配:真正的

现在,您可以使用TwitterClient服务立即控制器:

1 2 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;使用ob娱乐下载\\FrameworkBundle\控制器\AbstractController;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\HttpFoundation\响应;使用ob娱乐下载\组件\路由\注释\路线;DefaultController扩展AbstractController{/ * * *@Route(“/推”,方法= {“POST”}) * /公共函数推特(TwitterClient美元twitterClient,请求美元请求):响应{/ /获取用户,美元,美元地位的“POST”数据美元twitterClient- >推特(美元用户,美元关键,美元状态);/ /……}}

这是自动!容器知道通过Rot13Transformer当创建服务作为第一个参数TwitterClient服务。

自动装配逻辑解释

自动装配是通过读取Rot13Transformertype-hintTwitterClient:

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

自动装配系统寻找一个服务其id type-hint完全匹配:所以App \ Util \ Rot13Transformer。在这种情况下,存在!当您配置Rot13Transformer服务,您使用它的完全限定类名作为其id。自动装配并不是魔法:它看起来的服务id匹配type-hint。如果你负载自动服务,每个服务的id是它的类名。

如果有服务id完全匹配的类型,将会抛出一个清晰异常。

自动装配是一个伟大的方式来自动配置和Symfony试图一样ob娱乐下载可预测的并尽可能的清晰。

使用别名来实现自动装配

配置自动装配的主要方式是创建一个id完全匹配它的类的服务。在前面的示例中,服务的idApp \ Util \ Rot13Transformer自动,它允许我们自动装配这种类型。

这也可以使用一个完成别名。假设由于某种原因,服务的idapp.rot13.transformer。在这种情况下,任何参数type-hinted类名(App \ Util \ Rot13Transformer)可以不再autowired的。

没问题!为了解决这个问题,你可以创建服务的id匹配的类添加一个服务别名:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13
#配置/ services.yaml服务:#……# id不是一个类,所以它不会被用于自动装配app.rot13.transformer:类:App \ Util \ Rot13Transformer#……#但这修复它!#“app.rot13。变压器`` service will be injected when< /span>#一个“应用程序\ Util \ Rot13Transformer“type-hint检测App \ Util \ Rot13Transformer:“@app.rot13.transformer”

这将创建一个服务“别名”,其idApp \ Util \ Rot13Transformer。谢谢,自动装配认为这和使用它Rot13Transformer类是type-hinted。

提示

所使用的别名是autowired的核心包允许服务。例如,MonologBundle创建一个服务的id日志记录器。但它也添加别名:Psr \ \ LoggerInterface日志指向日志记录器服务。这就是为什么参数type-hintedPsr \ \ LoggerInterface日志可以autowired的。

使用接口

你也可能发现自己类型提示抽象(如接口)而不是具体类,因为它取代你的依赖与其他对象。

遵循这些最佳实践,假设你决定创建一个TransformerInterface:

1 2 3 4 5 6 7
/ / src / Util / TransformerInterface.php名称空间应用程序\跑龙套;接口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 (App \ Util \ TransformerInterface)不再匹配的id服务(App \ Util \ Rot13Transformer)。这意味着不再autowired的论证。

为了解决这个问题,添加一个别名:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9
#配置/ services.yaml服务:#……App \ Util \ Rot13Transformer:~#“App \ Util \ Rot13Transformer“服务时将被注入#一个“应用程序\ Util \ TransformerInterface“type-hint检测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 10
/ / src / Util / UppercaseTransformer.php名称空间应用程序\跑龙套;UppercaseTransformer实现了TransformerInterface{公共函数变换(字符串美元价值):字符串{返回strtoupper (美元价值);}}

如果你注册这个服务,你现在有了两个服务实现App \ Util \ TransformerInterface类型。自动装配子系统不能决定使用哪一个。记住,自动装配不是魔法;它看起来的一个服务id匹配type-hint。所以你需要选择一个类型的通过创建一个别名(见正确的服务id自动定义服务依赖关系(自动装配))。另外,你可以定义多个命名自动装配别名如果你想使用一个实现在某些情况下,在其他一些情况下和另一个实现。

例如,您可能想要使用Rot13Transformer默认情况下,当实现TransformerInterface接口类型的暗示,但使用UppercaseTransformer在一些特定的情况下实现。为此,您可以创建一个正常的别名TransformerInterface接口Rot13Transformer,然后创建一个叫自动装配的别名从一个特殊的字符串包含接口后面跟着一个变量名称匹配你的使用在注射时:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/ / src /服务/ MastodonClient.php名称空间应用程序\服务;使用应用程序\跑龙套\TransformerInterface;MastodonClient{私人美元变压器;公共函数__construct(TransformerInterface美元shoutyTransformer){美元- >变压器=美元shoutyTransformer;}公共函数嘟嘟声(用户美元用户、字符串美元关键、字符串美元状态):无效{美元transformedStatus=美元- >变压器- >变换(美元状态);/ /……连接到乳齿象,把转换后的状态}}
  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日24日25日26日
#配置/ services.yaml服务:#……App \ Util \ Rot13Transformer:~App \ Util \ UppercaseTransformer:~#“App \ Util \ UppercaseTransformer”服务#注入当一个“App \ Util \ TransformerInterface ' '为“# type-hint shoutyTransformer美元“参数检测。App \ Util \ TransformerInterface$ shoutyTransformer:“@App \ Util \ UppercaseTransformer”#如果用于注射的参数不匹配,但是# type-hint仍然匹配,“App \ Util \ Rot13Transformer ' '#服务将被注入。App \ Util \ TransformerInterface:“@App \ Util \ Rot13Transformer”应用程序服务\ \ TwitterClient:# Rot13Transformer将作为美元的变压器参数传递自动装配:真正的#如果你想选择非默认服务,不#想要使用一个命名的自动装配别名,手动线:#参数:# $变压器:“@App \ Util \ UppercaseTransformer”#……

多亏了App \ Util \ TransformerInterface别名,任何争论type-hinted与此接口将被通过了App \ Util \ Rot13Transformer服务。如果参数是命名shoutyTransformer美元,App \ Util \ UppercaseTransformer将使用。但是,你也可以手动线任何其他服务通过指定参数下的参数键。

修复Non-Autowireable参数

是一个自动装配只能当你的论点对象。但是如果你有一个标量参数(如字符串),这不能autowired: Symfony将抛出一个清晰异常。ob娱乐下载

为了解决这个问题,你可以手动线有问题的争论。你线困难的争论,Symfony照顾休息。ob娱乐下载

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

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

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

自动装配会自动调用任何方法与#[要求]每个参数属性上面,自动装配。如果你需要手动线的一些参数的方法,你可以明确配置方法调用

如果您的PHP版本不支持属性(他们介绍PHP 8),您可以使用@ required注释。

5.2

#[要求]属性是在Symfony 5.2中引入的。ob娱乐下载

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

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

5.1

公共类型属性自动装配是在Symfony 5.1中引入的。ob娱乐下载

自动装配控制器动作方法

如果你使用Symfony框架,你还可以自ob娱乐下载动装配参数控制器动作的方法。这是自动装配的特殊情况,为了方便存在。看到控制器为更多的细节。

性能的影响

由于Symfony的ob娱乐下载容器,编译没有使用自动装配的性能损失。然而,有一个小的性能损失dev环境,尽可能经常容器可能重建修改类。如果重建你的容器是缓慢(可能非常大的项目),你可能无法使用自动装配。

公众和可重用的包

公共bundle应该显式配置其服务,而不是依靠自动装配。自动装配取决于容器和包中可用的服务无法控制应用程序的服务容器中。你可以使用自动装配,以构建可重用的包在你的公司,你有完全控制所有的代码。

这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。
ob娱乐下载Symfony 5.4支持通过私人Packagist