服务容器

编辑本页

警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 4.1,现已不再维护。

本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。

服务容器

截屏视频

你更喜欢视频教程吗?请查看ob娱乐下载Symfony Fundamentals系列截图

您的申请是完整的一个“Mailer”对象可以帮助你发送电子邮件,而另一个对象可以帮助你将东西保存到数据库中。几乎一切你的应用“做”实际上是由这些对象之一完成的。每次你安装一个新的包,你就可以访问更多!

在Syob娱乐下载mfony中,调用这些有用的对象服务每个服务都存在于一个非常特殊的对象中服务容器.容器允许您集中构造对象的方式。它使您的生活更轻松,促进强大的架构和超级快!

获取和使用服务

当你启动Symfony应用时,你的容器ob娱乐下载已经包含许多服务。这些就像工具:等着你去利用它们。在你的控制器中,你可以从容器中“请求”一个服务,方法是用服务的类名或接口名作为参数的类型提示。想要日志什么东西吗?没有问题:

12 3 4 5 6 7 8 9 10 11 12 13 14
/ / src /控制器/ ProductController.php/ /……使用Psr日志LoggerInterface/ * * *@Route(“产品”)* /公共函数列表(LoggerInterface日志记录器日志记录器->信息(“看!我只是使用了一项服务。”);/ /……

还有其他服务吗?通过运行来找到答案:

12 3 4 5 6 7 8 9 10 11 12 13
PHP bin/控制台调试:自动装配#这只是一个输出的小样本…========================================================== ================================== 类/接口类型别名服务ID  ========================================================== ================================== Psr \ \ CacheItemPoolInterface缓存别名“cache.app.recorder”Psr \ \ LoggerInterface日志别名“monolog.logger”ob娱乐下载Symfony \ \ EventDispatcher \ EventDispatcherInterface组件别名“debug.event_dispatcher”ob娱乐下载Symfony \ \ HttpFoundation \ RequestStack组件别名“request_stack”ob娱乐下载Symfony \ \ HttpFoundation \会议\ SessionInterface组件别名“会话”ob娱乐下载Symfony \ \路由\ RouterInterface组件别名“router.default”========================================================== ==================================

当你在控制器方法中使用这些类型提示时自己的服务, ob娱乐下载Symfony将自动向您传递与该类型匹配的服务对象。

在整个文档中,您将看到如何使用容器中的许多不同服务。

提示

实际上有许多容器中有更多的服务,并且每个服务在容器中都有唯一的id,例如会话router.default.要获得完整的列表,可以运行PHP bin/控制台调试:容器.但大多数时候,你不需要担心这个。看到服务容器.看到如何调试服务容器和列表服务

在容器中创建/配置服务

你也可以组织你的自己的编码到服务中。例如,假设您需要向用户显示一条随机的、愉快的消息。如果你把这个代码放在控制器中,它就不能被重用。相反,你决定创建一个新类:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src /服务/ MessageGenerator.php名称空间应用程序服务MessageGenerator公共函数getHappyMessage()消息= (“你做到了!”您更新了系统!神奇的!”“这是我今天看到的最酷的更新之一!”“伟大的工作!继续前进!”,);指数=(用于消息);返回消息指数];}}

恭喜你!您刚刚创建了您的第一个服务类!你可以立即在你的控制器中使用它:

12 3 4 5 6 7 8 9 10 11 12
使用应用程序服务MessageGenerator公共函数(MessageGeneratormessageGenerator//由于类型提示,容器将实例化一个// new MessageGenerator并将它传递给你!/ /……消息messageGenerator->getHappyMessage ();->addFlash (“成功”消息);/ /……

当你要求MessageGenerator服务时,容器构造一个新的MessageGenerator对象并返回它(请参阅下面的边栏)。但如果你从不主动要求,那就从来没有构造:节省内存和速度。作为奖励,MessageGenerator服务只创建一次:每次请求都会返回相同的实例。

文档假设欧宝官网下载app您正在使用以下服务配置,这是新项目的默认配置:

  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#配置/ services.yaml服务:# this*文件中服务的默认配置_defaults:自动装配:真正的#自动在服务中注入依赖项。可以使用autoconfigure:真正的#自动注册你的服务为命令,事件订阅者等。公众:#允许通过删除未使用的服务来优化容器;这也意味着#直接从容器中获取服务通过$container->get()将不起作用。#最好的做法是明确你的依赖关系。#使src/中的类可用作服务#这将为每个类创建一个服务,其id为全限定类名App \:资源:“. . / src / *”排除:“. . / src /{实体,迁移、测试Kernel.php}’#……

提示

的值资源而且排除选项可以是任何有效的一团模式.的值排除Option也可以是glob模式的数组。

4.2

对象传递glob模式数组的特性排除选项在Symfony 4.2中引入。ob娱乐下载

类中的任何类都可以自动使用src /目录即服务,无需手动配置。稍后,您将在服务容器

如果您更喜欢手动连接您的服务,这是完全可能的:参见服务容器

向服务中注入服务/配置

如果您需要访问日志记录器内部服务MessageGenerator?没问题!创建一个__construct ()方法。美元记录器参数的LoggerInterfacetype-hint。将此设置为new美元记录器属性并在以后使用它:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
/ / src /服务/ MessageGenerator.php/ /……使用Psr日志LoggerInterfaceMessageGenerator私人日志记录器公共函数__construct(LoggerInterface日志记录器->记录器=日志记录器;}公共函数getHappyMessage()->日志记录器->信息(“马上就能找到快乐的消息了!”);/ /……}}

就是这样!容器会自动知道如何通过日志记录器实例化MessageGenerator.它怎么知道要这么做?自动装配.关键在于LoggerInterface输入提示__construct ()方法和自动装配:真配置在services.yaml.当您输入参数提示时,容器将自动找到匹配的服务。如果不能,您将看到一个明确的异常和有用的建议。

顺便说一下,这种方法添加依赖到您的__construct ()方法。依赖注入.对于一个简单的概念来说,这是个可怕的术语。

你应该如何知道使用LoggerInterface对于输入提示?你可以阅读文档中的任何你正在使用的功能,或者通过运行以下命令来获得自动连接的类型提示列表:

1
PHP bin/控制台调试:自动装配

这个命令是您最好的朋友。这是输出的一个小子集:

类/接口类型 服务ID
Psr \ \ CacheItemPoolInterface缓存 “cache.app.recorder”的别名
Psr \ \ LoggerInterface日志 “monologo .logger”的别名
ob娱乐下载Symfony \ \ EventDispatcher \ EventDispatcherInterface组件 “debug.event_dispatcher”的别名
ob娱乐下载Symfony \ \ HttpFoundation \ RequestStack组件 request_stack的别名
ob娱乐下载\组件\ HttpFoundation\会话\ SessionInterface “会话”的别名
ob娱乐下载Symfony \ \路由\ RouterInterface组件 router.default的别名

处理多业务

假设您还希望在每次进行站点更新时向站点管理员发送电子邮件。为此,你创建了一个新类:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/ / src /更新/ SiteUpdateManager.php名称空间应用程序更新使用应用程序服务MessageGeneratorSiteUpdateManager私人messageGenerator私人梅勒公共函数__construct(MessageGeneratormessageGenerator, \ Swift_Mailer梅勒->messageGenerator =messageGenerator->梅勒=梅勒;}公共函数notifyOfSiteUpdate()happyMessage->messageGenerator->getHappyMessage ();消息= (\ Swift_Message (“网站刚刚更新!”))->setFrom (“admin@example.com”->该太空站(“manager@example.com”->addPart (有人刚刚更新了网站。我们告诉他们:“happyMessage);返回->梅勒->发送(消息) >0;}}

这需要MessageGenerator而且Swift_Mailer服务。没问题!事实上,这个新服务已经可以使用了。例如,在控制器中,您可以键入提示newSiteUpdateManager类并使用它:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
/ / src /控制器/ SiteController.php/ /……使用应用程序更新SiteUpdateManager公共函数(SiteUpdateManagersiteUpdateManager/ /……如果siteUpdateManager->notifyOfSiteUpdate ()) {->addFlash (“成功”“通知邮件发送成功。”);}/ /……

多亏了自动装配和输入提示__construct (),容器创建SiteUpdateManager对象并将正确的参数传递给它。在大多数情况下,这是完美的。

手动连接参数

但是在少数情况下,服务的参数不能自动连接。例如,假设你想让管理电子邮件可配置:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// src/Updates/SiteUpdateManager.php //…类SiteUpdateManager{//…+ private $adminEmail;——公共函数__construct(MessageGenerator $ MessageGenerator, \Swift_Mailer $mailer)+公共函数__construct(MessageGenerator $ MessageGenerator, \Swift_Mailer $mailer, $adminEmail){//…+ $this->adminEmail = $adminEmail;}公共函数notifyOfSiteUpdate(){//…$message = \Swift_Message::newInstance() //…——>太空站(manager@example.com)+ - >太空站($ this - > adminEmail)/ /……;/ /……}}

如果你做了这个更改并刷新,你会看到一个错误:

不能自动装配服务"AppUpdatesSiteUpdateManager":方法"__construct()"的参数"$adminEmail"必须有一个类型提示或显式给出一个值。

这很有道理!容器不可能知道你想在这里传递什么值。没问题!在你的配置中,你可以显式地设置这个参数:

  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13
#配置/ services.yaml服务:#……#与之前相同App \:资源:“. . / src / *”排除:“. . / src /{实体、迁移、测试}'#显式配置服务应用程序更新\ \ SiteUpdateManager:参数:$ adminEmail:“manager@example.com”

多亏了这一点,容器才会通过manager@example.comadminEmail美元的观点__construct当创建SiteUpdateManager服务。其他参数仍然是自动连接的。

但是,这不是很脆弱吗?幸运的是,不!如果你重命名adminEmail美元对其他事物的争论。mainEmail美元-当你重新加载下一页时,你会得到一个明确的异常(即使该页没有使用此服务)。

服务参数

除了保存服务对象外,容器还保存名为参数.方法下添加参数即可创建参数参数键并使用% parameter_name %语法:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10
#配置/ services.yaml参数:admin_email:manager@example.com服务:#……应用程序更新\ \ SiteUpdateManager:参数:$ adminEmail:“% admin_email %”

实际上,一旦定义了参数,就可以通过% parameter_name %语法在任何其他配置文件。类中定义了许多参数配置/ services.yaml文件。

然后你可以在服务中获取参数:

1 2 3 4 5 6 7 8 9 10 11
SiteUpdateManager/ /……私人adminEmail公共函数__constructadminEmail->adminEmail =adminEmail;}}

你也可以直接从容器中获取参数:

1 2 3 4 5 6 7 8 9 10
公共函数()/ /……//这只适用于你扩展基本控制器adminEmail->容器->getParameter (“admin_email”);//或者更近的路!// $adminEmail = $this->getParameter('admin_email');

有关参数的详细信息,请参见参数简介

选择特定的服务

MessageGenerator前面创建的服务需要LoggerInterface论点:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
/ / src /服务/ MessageGenerator.php/ /……使用Psr日志LoggerInterfaceMessageGenerator私人日志记录器公共函数__construct(LoggerInterface日志记录器->记录器=日志记录器;}/ /……

然而,有多个容器中的服务LoggerInterface,例如日志记录器monolog.logger.requestmonolog.logger.php等。容器如何知道使用哪一个?

在这些情况下,容器通常配置为自动选择其中一个服务日志记录器在这种情况下(阅读更多关于为什么在自动定义服务依赖关系(自动装配)).但是,你可以控制它并传入一个不同的记录器:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11
#配置/ services.yaml服务:#……代码和之前一样#显式配置服务应用程序服务\ \ MessageGenerator:参数:“@”符号很重要:它告诉容器#你想传递id为' monoog .logger.request'的服务#而不仅仅是*string* ' monoo .logger.request'日志:美元“@monolog.logger.request”

这告诉容器美元记录器参数__construct是否应该使用id为的服务monolog.logger.request

的完整列表所有容器中可能的服务,运行:

1
PHP bin/控制台调试:容器

根据名称或类型绑定参数

你也可以使用绑定关键字按名称或类型绑定特定参数:

  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#配置/ services.yaml服务:_defaults:绑定:#将此值传递给任何服务的任何$adminEmail参数在这个文件中定义的#(包括控制器参数)$ adminEmail:“manager@example.com”#将此服务传递给任意$requestLogger参数该文件中定义的# service$ requestLogger:“@monolog.logger.request”#为任何LoggerInterface类型传递此服务该文件中定义的# servicePsr \ Log \ LoggerInterface:“@monolog.logger.request”#……

通过把绑定关键在_defaults的值任何理由任何该文件中定义的服务!你可以通过名称绑定参数(例如:adminEmail美元)或按类型(例如:Psr \ \ LoggerInterface日志).

绑定配置也可以应用于特定的服务,或者在一次加载多个服务时(例如:服务容器).

获取作为服务的容器参数

4.1

以服务形式获取容器参数的特性是在Symfony 4.1中引入的。ob娱乐下载

如果某些服务或控制器需要大量容器参数,有一种更简单的替代方法,可以将所有容器参数绑定到services._defaults.bind选择。类型提示其构造函数的任何参数ParameterBagInterface或者新的ContainerBagInterface服务将获取容器中的所有参数ParameterBag对象:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
/ / src /服务/ MessageGenerator.php/ /……使用ob娱乐下载组件DependencyInjectionParameterBagParameterBagInterfaceMessageGenerator私人参数个数公共函数__construct(ParameterBagInterface参数个数->params =参数个数;}公共函数someMethod()//从$this->params获取任何参数,存储所有容器参数发送方->参数个数->get (“mailer_sender”);/ /……}}

自动连线选项

以上,services.yaml文件自动装配:真_defaults节,使其应用于该文件中定义的所有服务。的类型中输入提示参数__construct ()方法和容器将自动向您传递正确的参数。这整个条目都是围绕自动装配编写的。

有关自动装配的更多详细信息,请查看自动定义服务依赖关系(自动装配)

autoconfigure选项

以上,services.yaml文件可以使用autoconfigure:真_defaults节,使其应用于该文件中定义的所有服务。通过此设置,容器将自动将某些配置应用到您的服务,基于您的服务.这是最常用的自动标记你的服务。

例如,要创建Twig扩展,您需要创建一个类,将其注册为服务,以及标签它与twig.extension

但是,与可以使用autoconfigure:真,你不需要标签。事实上,如果你在用默认的服务。yaml配置,你不需要这样做任何东西:服务将自动加载。然后,可以使用autoconfigure将添加twig.extension标签你,因为你的类实现了树枝\ \ ExtensionInterface延伸.感谢自动装配,您甚至可以添加构造函数参数而不需要任何配置。

公共服务与私人服务

多亏了_defaults部分services.yaml,此文件中定义的每个服务都是公众:假默认情况下。

这是什么意思?当一项服务Public,您可以直接从容器对象访问它,它可以从任何扩展的控制器访问控制器

1 2 3 4 5 6 7 8 9 10 11
使用应用程序服务MessageGenerator/ /……公共函数()//容器中有一个公共的"logger"服务日志记录器->容器->get (“日志”);//这将不起作用:MessageGenerator是私有服务发电机->容器->get (MessageGenerator::类);}

作为最佳实践,您应该只创建私人服务,这将自动发生。而且,你应该这样做使用集装箱- > get ()方法获取公共服务。

但是,如果你需要将服务设为公共,则重写公共设置:

  • YAML
  • XML
1 2 3 4 5 6 7
#配置/ services.yaml服务:#……代码和之前一样#显式配置服务应用程序服务\ \ MessageGenerator:公众:真正的

同时使用资源导入多个服务

方法可以同时导入多个服务资源关键。例如,默认的Symfony配置包含:ob娱乐下载

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9
#配置/ services.yaml服务:#……#使src/中的类可用作服务#这将为每个类创建一个服务,其id为全限定类名App \:资源:“. . / src / *”排除:“. . / src /{实体、迁移、测试}'

提示

的值资源而且排除选项可以是任何有效的一团模式

这可用于快速将许多类作为服务提供,并应用一些默认配置。的id每个服务的全限定类名。你可以通过下面的id(类名)覆盖任何被导入的服务服务容器).如果你重写一个服务,没有一个选项(例如。公共)从导入继承(但覆盖的服务仍然继承_defaults).

你也可以排除特定的路径。方法中的性能略有提高,但这是可选的dev环境:排除的路径不会被跟踪,因此修改它们不会导致容器被重新构建。

请注意

等等,这是不是意味着每一个src /是否注册为服务?甚至是模型课程?事实上,没有。只要你有公众:假在你的_defaults键(或者您可以将其添加到特定的导入下),所有导入的服务都是私人.多亏了这一点,所有的课程src /这是显式地作为服务使用会自动从最终容器中删除。实际上,导入意味着所有的类都是“可用的”使用作为服务,而不需要手动配置。

使用相同命名空间的多个服务定义

如果你使用YAML配置格式定义服务,PHP命名空间被用作每个配置的键,所以你不能在同一个命名空间下为类定义不同的服务配置:

1 2 3 4 5
#配置/ services.yaml服务:应用程序域\ \:资源:“. . / src /域/ *”#……

为了拥有多个定义,请添加名称空间选项,并使用任何唯一的字符串作为每个服务配置的键:

1 2 3 4 5 6 7 8 9 10 11
#配置/ services.yaml服务:command_handlers:名称空间:应用程序域\ \资源:“. . / src /域/ * / CommandHandler '标签:(command_handler)event_subscribers:名称空间:应用程序域\ \资源:“. . / src /域/ * / EventSubscriber '标签:(event_subscriber)

显式配置服务和参数

在Symfony ob娱乐下载3.3之前,所有服务和(通常)参数都是显式配置的:这是不可能的自动加载服务而且自动装配不太常见。

这两个特性都是可选的。即使您使用它们,也可能在某些情况下希望手动连接服务。例如,假设您想要注册2SiteUpdateManager类-每个类都有不同的管理电子邮件。在这种情况下,每个服务都需要有一个唯一的服务id:

  • 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 26
#配置/ services.yaml服务:#……这是服务的idsite_update_manager.superadmin:类:应用\ \ SiteUpdateManager更新#你仍然可以使用自动装配:我们只是想展示它看起来像没有自动装配:#手动连接所有参数参数:-“@App \ \ MessageGenerator服务”-“@mailer”-“superadmin@example.com”site_update_manager.normal_users:类:应用\ \ SiteUpdateManager更新自动装配:参数:-“@App \ \ MessageGenerator服务”-“@mailer”-“contact@example.com”#创建一个别名,这样-默认情况下-如果你输入-hint SiteUpdateManager# site_update_manager将使用超级管理员应用程序更新\ \ SiteUpdateManager:“@site_update_manager.superadmin”

在这种情况下,两个注册服务:site_update_manager.superadmin而且site_update_manager.normal_users.多亏了别名,如果你输入提示SiteUpdateManager第一个(site_update_manager.superadmin)将获通过。如果你想通过第二关,你就得这么做手动连接服务

谨慎

如果有的话创建别名和从src/加载所有服务,然后三个服务已经创建(自动服务+您的两个服务),自动加载的服务将在您输入-hint时被传递(默认情况下)SiteUpdateManager.这就是为什么创建别名是一个好主意。

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