服务容器
编辑本页警告:您正在浏览的文档欧宝官网下载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;公共函数新(MessageGenerator$messageGenerator){//由于类型提示,容器将实例化一个// new MessageGenerator并将它传递给你!/ /……$消息=$messageGenerator->getHappyMessage ();$这->addFlash (“成功”,$消息);/ /……}
当你要求MessageGenerator
服务时,容器构造一个新的MessageGenerator
对象并返回它(请参阅下面的边栏)。但如果你从不主动要求,那就从来没有构造:节省内存和速度。作为奖励,MessageGenerator
服务只创建一次:每次请求都会返回相同的实例。
向服务中注入服务/配置
如果您需要访问日志记录器
内部服务MessageGenerator
?没问题!创建一个__construct ()
方法。美元记录器
参数的LoggerInterface
type-hint。将此设置为new美元记录器
属性并在以后使用它:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
/ / src /服务/ MessageGenerator.php/ /……使用Psr\日志\LoggerInterface;类MessageGenerator{私人$日志记录器;公共函数__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娱乐下载 |
“会话”的别名 |
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名称空间应用程序\更新;使用应用程序\服务\MessageGenerator;类SiteUpdateManager{私人$messageGenerator;私人$梅勒;公共函数__construct(MessageGenerator$messageGenerator, \ 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;公共函数新(SiteUpdateManager$siteUpdateManager){/ /……如果($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.com
到adminEmail美元
的观点__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;公共函数__construct($adminEmail){$这->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\日志\LoggerInterface;类MessageGenerator{私人$日志记录器;公共函数__construct(LoggerInterface$日志记录器){$这->记录器=$日志记录器;}/ /……}
然而,有多个容器中的服务LoggerInterface
,例如日志记录器
,monolog.logger.request
,monolog.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娱乐下载\组件\DependencyInjection\ParameterBag\ParameterBagInterface;类MessageGenerator{私人$参数个数;公共函数__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之前,所有服务和(通常)参数都是显式配置的:这是不可能的自动加载服务而且自动装配不太常见。
这两个特性都是可选的。即使您使用它们,也可能在某些情况下希望手动连接服务。例如,假设您想要注册2为SiteUpdateManager
类-每个类都有不同的管理电子邮件。在这种情况下,每个服务都需要有一个唯一的服务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
.这就是为什么创建别名是一个好主意。