服务容器

编辑该页面

警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 4.2,不再维护。

这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。

服务容器

截屏视频

你喜欢视频教程?检查ob娱乐下载Symfony基本面视频系列

您的应用程序完整的有用的对象:一个“梅勒”对象可能会帮助您发送电子邮件,而另一个对象可能会帮助你保存到数据库中。几乎一切应用程序“确实”实际上是由这些对象之一。每一次你安装一个新的包,你获得更多!

在Syob娱乐下载mfony中,这些被称为有用的对象服务和每个服务的生活在一个非常特殊的对象称为服务容器。容器允许你集中对象的构造方式。它使你的生活更容易,促进一个强壮的架构和超级快!

获取和使用服务

当你开始一个Symfony应用,你的容器ob娱乐下载已经包含了许多服务。这些都是像工具:等你来利用它们。在控制器中,可以“问”服务的容器类型提示一个论点与服务的类或接口的名称。想要日志什么东西吗?没有问题:

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

提供哪些服务?发现通过运行:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
美元php bin /控制台调试:自动装配#这是*小*样本的输出……描述了一个logger实例。Psr \ Log \ LoggerInterface (monolog.logger)请求堆栈控制请求的生命周期。ob娱乐下载Symfony \组件\ HttpFoundation \ RequestStack (request_stack)接口会话。ob娱乐下载Symfony组件\ \ HttpFoundation \会议\ SessionInterface(会话)RouterInterface所有路由器类必须实现的接口。ob娱乐下载Symfony \组件\ \ RouterInterface路由(router.default) […]

当你使用这些类型提示你的控制器方法或在你自己的服务,Sob娱乐下载ymfony会自动通过你的服务对象匹配类型。

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

提示

实际上有许多更多的服务容器,容器中的每个服务都有一个惟一的id,会话router.default。对于一个完整的列表,您可以运行php bin /控制台调试:容器。但是大多数时候,你不需要担心这个。看到服务容器。看到如何调试服务容器&列表服务

创建/配置服务的容器

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

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

恭喜你!你刚刚创建的第一个服务类!你可以用它立即内部控制器:

1 2 3 4 5 6 7 8 9 10 11 12
使用应用程序\服务\MessageGenerator;公共函数(MessageGenerator美元messageGenerator){/ /由于type-hint,容器将实例化一个/ /新MessageGenerator并将其传递给你!/ /……美元消息=美元messageGenerator- >getHappyMessage ();美元- >addFlash (“成功”,美元消息);/ /……}

当你问的MessageGenerator服务,构造一个新的容器MessageGenerator下面的对象,并返回该对象(参见侧栏)。但是如果你从来没有要求服务,它是从来没有构造:节省内存和速度。作为奖励,MessageGenerator只有创建服务一次:返回相同的实例每次询问。

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

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

提示

的值资源排除可以是任何有效的选项一团模式。的值排除一团模式的选择也可以是一个数组。

由于这种配置,您可以自动使用任何类的src /目录服务,无需手动配置。之后,您将了解更多关于这个服务容器

如果你想手动线服务,这是完全可能的:明白了服务容器

注入服务/配置服务

如果你需要访问日志记录器从内部服务MessageGenerator吗?没问题!创建一个__construct ()方法美元记录器论点的LoggerInterfacetype-hint。设置一个新的美元记录器财产和使用它后:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/ / src /服务/ MessageGenerator.php/ /……使用Psr\日志\LoggerInterface;MessageGenerator{私人美元日志记录器;公共函数__construct(LoggerInterface美元日志记录器){美元- >记录器=美元日志记录器;}公共函数getHappyMessage(){美元- >日志记录器- >信息(要找到一个快乐的消息!”);/ /……}}

就是这样!容器将自动知道通过日志记录器服务实例化时MessageGenerator。它是如何知道要做到这一点吗?自动装配。的关键是LoggerInterfacetype-hint在你__construct ()方法和自动装配:真配置在services.yaml。type-hint论点时,容器会自动找到匹配服务。如果不能,你会看到一个明确的例外,一个有用的建议。

顺便说一下,这将依赖项添加到您的方法__construct ()方法被调用依赖注入。这是一个可怕的词,一个简单的概念。

你应该知道如何使用LoggerInterfacetype-hint吗?你可以读任何特性的文档你使用,或得到一个autowireable列表类型提示通过运行:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
美元php bin /控制台调试:自动装配#这是*小*样本的输出……描述了一个logger实例。Psr \ Log \ LoggerInterface (monolog.logger)请求堆栈控制请求的生命周期。ob娱乐下载Symfony \组件\ HttpFoundation \ RequestStack (request_stack)接口会话。ob娱乐下载Symfony组件\ \ HttpFoundation \会议\ SessionInterface(会话)RouterInterface所有路由器类必须实现的接口。ob娱乐下载Symfony \组件\ \ RouterInterface路由(router.default) […]

处理多个服务

假设你还想邮件站点管理员每次网站更新。要做到这一点,你创建一个新类:

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日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;}}

这需要MessageGeneratorSwift_Mailer服务。那是没有问题!事实上,可以使用这个新服务。在一个控制器,例如,你可以type-hint新SiteUpdateManager类并使用它:

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

由于自动装配和类型提示__construct (),容器创建SiteUpdateManager对象并将其传递正确的论点。在大多数情况下,这是完美的。

手动布线参数

但有一些情况下,当一个参数不能autowired的服务。例如,假设您想要管理电子邮件可配置:

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日27日28
/ / src /更新/ SiteUpdateManager.php/ /……类SiteUpdateManager {/ /……+私人adminEmail美元;——公共职能__construct (MessageGenerator MessageGenerator美元\ Swift_Mailer梅勒美元)+公共职能__construct (MessageGenerator MessageGenerator美元,美元\ Swift_Mailer梅勒,adminEmail美元){/ /……+ $ this - > adminEmail = $ adminEmail;}公共职能notifyOfSiteUpdate () {/ /……消息= \ Swift_Message:美元:newInstance () / /……- - >太空站(manager@example.com)+ - >太空站($ this - > adminEmail)/ /……;/ /……}}

如果你把这种变化和更新,您将看到一个错误:

不能自动装配服务“AppUpdatesSiteUpdateManager”:参数“adminEmail美元”的方法“__construct()”必须有一个明确type-hint或被赋予一个值。

这是有道理的!没有办法,你想通过这里容器知道价值。没问题!在您的配置,您可以显式地设置这个参数:

  • YAML
  • XML
  • PHP
1 2 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服务。其他参数仍将autowired的。

但是,这不是脆弱吗?幸运的是,不!如果您重命名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
公共函数(){/ /……/ /这个快捷方式只适用AbstractController如果你扩展基地美元adminEmail=美元- >getParameter (“admin_email”);/ /这是等价的代码之前的快捷方式:/ / $ adminEmail = $ this - >容器- >获得(parameter_bag) - > (“admin_email”);}

关于参数的更多信息,请参阅介绍了参数

选择一个特定的服务

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

1 2 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是‘monolog.logger.request’,#而不仅仅是*字符串*“monolog.logger.request”日志:美元“@monolog.logger.request”

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

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

1
美元php bin /控制台调试:容器

通过名称或类型绑定参数

您还可以使用绑定关键字绑定特定参数的名字或类型:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#配置/ services.yaml服务:_defaults:绑定:# adminEmail美元将该值传递给任何理由任何服务#在这个文件中定义的(包括控制器参数)$ adminEmail:“manager@example.com”#该服务传递给任何requestLogger美元的理由#在这个文件中定义的服务$ requestLogger:“@monolog.logger.request”#通过这个服务对于任何LoggerInterface type-hint任何#在这个文件中定义的服务Psr \ Log \ LoggerInterface:“@monolog.logger.request”#选择您可以定义的参数的名称和类型匹配字符串$ adminEmail:“manager@example.com”Psr \ \ LoggerInterface日志$ requestLogger:“@monolog.logger.request”#……

通过将绑定关键在_defaults,您可以指定的值任何理由任何在这个文件中定义的服务!你可以绑定参数的名字(如。adminEmail美元),按类型(如。Psr \ \ LoggerInterface日志)或(如。Psr \ Log \ LoggerInterface requestLogger美元)。

绑定配置还可以应用于特定的服务或装船时很多服务(即。服务容器)。

容器参数作为服务

如果某些服务或控制器需要大量容器参数,有更简单的选择绑定的services._defaults.bind选择。Type-hint其构造函数参数ParameterBagInterface或新ContainerBagInterface和服务将得到所有容器参数ParameterBag对象:

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

自动装配选项

以上,services.yaml文件自动装配:真_defaults节,适用于所有在该文件中定义的服务。这个设置,你可以type-hint参数__construct ()方法,你的服务和容器会自动将你正确的参数。整个条目已经写在自动装配。

关于自动装配的更多细节,请查看自动定义服务依赖关系(自动装配)

可以使用autoconfigure选项

以上,services.yaml文件可以使用autoconfigure:真_defaults节,适用于所有在该文件中定义的服务。经过这样设置后,容器会自动应用某些配置到你的服务,根据您的服务的。这主要是用于自动标记你的服务。

例如,创建一个分支扩展,您需要创建一个类,它作为一个服务注册,和标签它与twig.extension

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

公共和私人服务

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

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

1 2 3 4 5 6 7 8 9 10 11
使用应用程序\服务\MessageGenerator;/ /……公共函数(){/ /有一个公开的“日志”服务的容器美元日志记录器=美元- >容器- >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 3ob娱乐下载.3之前,所有服务和(通常)参数显式配置:这是不可能的负载自动服务自动装配不常见得多。

这两种功能是可选的。即使你使用它们,可能会有一些情况下,你想要手动线服务。例如,假设你想注册2服务SiteUpdateManager类——每一个都有不同的管理邮件。在这种情况下,每个需要有一个独特的服务id:

  • 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服务:#……#这是服务的idsite_update_manager.superadmin:类:应用\ \ SiteUpdateManager更新#你仍然可以使用自动装配:我们只是想告诉它是什么样子自动装配:#手动线所有参数参数:- - - - - -“@App \ \ MessageGenerator服务”- - - - - -“@mailer”- - - - - -“superadmin@example.com”site_update_manager.normal_users:类:应用\ \ SiteUpdateManager更新自动装配:参数:- - - - - -“@App \ \ MessageGenerator服务”- - - - - -“@mailer”- - - - - -“contact@example.com”#创建一个别名,因此,默认情况下,如果你type-hint SiteUpdateManager,# site_update_manager。超级管理员将使用几个应用程序更新\ \ SiteUpdateManager:“@site_update_manager.superadmin”

在这种情况下,两个服务注册:site_update_manager.superadminsite_update_manager.normal_users。由于别名,如果你type-hintSiteUpdateManager第一个(site_update_manager.superadmin)将被通过。如果你想通过第二个,你需要手动线服务

谨慎

如果你做创建别名和从src /加载所有服务,然后三个服务创建(自动服务+你的两个服务)和自动加载服务将被传递——默认情况下,当你type-hintSiteUpdateManager。这就是为什么创建别名是一个好主意。

这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。