服务容器

编辑该页面

警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 3.4,不再维护。

这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。

服务容器

截屏视频

你喜欢视频教程?检查欧宝娱乐app下载地址Symfony基本面视频系列

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

在Sy欧宝娱乐app下载地址mfony中,这些被称为有用的对象服务和每个服务的生活在一个非常特殊的对象称为服务容器。如果你有服务容器,那么您可以获取服务,通过该服务的id:

1 2
美元日志记录器=美元容器- >get (“日志”);美元entityManager=美元容器- >get (“doctrine.orm.entity_manager”);

容器允许你集中对象的构造方式。它使你的生活更容易,促进一个强壮的架构和超级快!

获取和使用服务

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

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

3.3

type-hint服务的能力,以获得在Symfony 3.3中引入的。欧宝娱乐app下载地址看到控制器章为更多的细节。

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
美元php bin /控制台调试:容器#这是*小*样本的输出……= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =服务ID类名称= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 欧宝娱乐app下载地址= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =教条主义\包\ DoctrineBundle \注册表文件系统Symfony \文件系统组件\ \文件系统形式。工厂Symfon欧宝娱乐app下载地址y \组件\ \ FormFactory记录器Symfony \桥形式\独白\记录器request_stack Symfony \ HttpFoundation \ RequestStack路由器Symfony \ \组件包\ \ FrameworkBundle \路由路由器安全。authorization_checker 欧宝娱乐app下载地址Symfony核心组件\ \安全\ \授权\ AuthorizationChecker安全。password_encoder 欧宝娱乐app下载地址Symfony核心组件\ \安全\ \编码器\ UserPasswordEncoder会话Symfony组件\ \ HttpFoundation \会议\会话翻译翻译Symfony \组件\ \ DataCollectorTranslator枝树枝\验证器\ \环境验证器Symfony \组件验证器\ ValidatorInterface = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

您还可以使用独特的“服务ID”直接访问服务:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ / src / AppBundle /控制器/ ProductController.php名称空间AppBundle\控制器;使用欧宝娱乐app下载地址\\FrameworkBundle\控制器\控制器;使用欧宝娱乐app下载地址\组件\路由\注释\路线;ProductController扩展控制器{/ * * *@Route(“产品”)* /公共函数listAction(){美元日志记录器=美元- >容器- >get (“日志”);美元日志记录器- >信息(“看!我只是使用一个服务”);/ /……}}

获取服务直接从容器中这样只如果你扩展控制器类。

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

等等!所有的服务(对象)实例化每一个请求吗?不!容器是懒惰:它才实例化一个服务(除非)你问。例如,如果你从来没有使用验证器服务请求时,容器不会实例化它。

创建/配置服务的容器

提示

推荐在Symfony 3.3配置服务的方式发生了改变。欧宝娱乐app下载地址深入的解释,明白了Symf欧宝娱乐app下载地址ony 3.3 DI容器变化解释(自动装配、_defaults等)

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

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

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

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

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

假设您正欧宝体育电话在使用的文档欧宝娱乐app下载地址services.yml Symfony标准版(版本3.3)配置。最重要的部分是:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# app / config / services.yml服务:# * *文件默认配置服务_defaults:自动装配:真正的可以使用autoconfigure:真正的公众:#让类在src / AppBundle可以用作服务AppBundle \:资源:“. . / . . / src / AppBundle / *’#你可以排除目录或文件#如果服务是未使用的,删除排除:“. . / . . / src / AppBundle /{实体,库}’

提示

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

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

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

3.3

_defaults关键从一个目录加载服务的能力在Symfony 3.3中添加。欧宝娱乐app下载地址

你也可以卖个服务直接从容器通过其“id”,在这种情况下将其类名:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
使用AppBundle\服务\MessageGenerator;/ /访问服务,比如这只如果你扩展控制器ProductController扩展控制器{公共函数newAction(){/ /只如果你的服务是公共的美元messageGenerator=美元- >get (MessageGenerator::类);美元消息=美元messageGenerator- >getHappyMessage ();美元- >addFlash (“成功”,美元消息);/ /……}}

然而,这只有如果你使你的服务工作公共

谨慎

是不区分大小写的(如服务id。AppBundle \ \ MessageGenerator服务appbundle \ \ messagegenerator服务指相同的服务)。但这是在Symfony 3.3中弃用。欧宝娱乐app下载地址从4.0开始,服务id将区分大小写的。

注入服务/配置服务

如果你需要访问日志记录器从内部服务MessageGenerator吗?你的服务直接访问容器,所以你不能通过取回它吗$ this - >容器- > get ()

没问题!相反,创建一个__construct ()方法美元记录器论点的LoggerInterfacetype-hint。设置一个新的美元记录器财产和使用它后:

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

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

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

1
美元php bin /控制台调试:自动装配

这只是一小部分的输出:

服务ID 类名
Psr \ \ CacheItemPoolInterface缓存 别名cache.app.recorder
Psr \ \ LoggerInterface日志 别名monolog.logger
欧宝娱乐app下载地址Symfony \ \ EventDispatcher \ EventDispatcherInterface组件 别名debug.event_dispatcher
欧宝娱乐app下载地址Symfony \ \ HttpFoundation \ RequestStack组件 别名request_stack
欧宝娱乐app下载地址\组件\ HttpFoundation\会话\ SessionInterface 别名会话
欧宝娱乐app下载地址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 / AppBundle /更新/ SiteUpdateManager.php名称空间AppBundle\更新;使用AppBundle\服务\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服务。只要你从src / AppBundle加载所有服务,您可以使用服务立即:

1 2 3 4 5 6 7 8 9 10 11 12
使用AppBundle\更新\SiteUpdateManager;公共函数newAction(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 / AppBundle /更新/ 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)/ /……;/ /……}}

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

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

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

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12
# app / config / services.yml服务:#……和以前一样AppBundle \:资源:“. . / . . / src / AppBundle / *’排除:“. . / . . / src / AppBundle /{实体,库}’#显式配置服务AppBundle \ \ SiteUpdateManager更新:参数:$ adminEmail:“manager@example.com”

3.3

可以配置一个参数通过它的名称(adminEmail美元)是在Symfony 3.3中引入的。欧宝娱乐app下载地址以前,你可以配置它只有通过指数(2在这种情况下),或者通过使用空引用的其他参数。

谢谢,容器将通过manager@example.com作为第三个参数__construct在创建SiteUpdateManager服务。其他参数仍将autowired的。

但是,这不是脆弱吗?幸运的是,不!如果您重命名adminEmail美元参数别的东西——如。mainEmail美元时,你会得到一个明确的异常重新加载下一页(即使该页面没有使用此服务)。

服务参数

除了服务对象,容器还拥有配置,叫做参数。创建一个参数,添加它参数关键和引用它% parameter_name %语法:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10
# app / config / services.yml参数:admin_email:manager@example.com服务:#……和以前一样AppBundle \ \ SiteUpdateManager更新:参数:$ adminEmail:“% admin_email %”

事实上,一旦你定义一个参数,它可以通过引用% parameter_name %语法在任何——像其他服务配置文件config.yml。许多参数定义在一个参数。yml文件

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

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
公共函数newAction(){/ /……/ /这只如果你扩展控制器美元adminEmail=美元- >容器- >getParameter (“admin_email”);/ /或更短!/ / $ adminEmail = $ this - > getParameter (“admin_email”);}

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

选择一个特定的服务

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/ / src / AppBundle /服务/ 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
# app / config / services.yml服务:#……同样的代码#显式配置服务AppBundle \服务\ MessageGenerator:参数:日志:美元“@monolog.logger.request”

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

提示

@符号是重要的:这就是你想通过告诉容器服务是谁的身份证monolog.logger.request,而不仅仅是字符串monolog.logger.request

通过名称或类型绑定参数

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

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

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

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

自动装配选项

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

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

可以使用autoconfigure选项

3.3

可以使用autoconfigure选项是在Symfony 3.3中引入的。欧宝娱乐app下载地址

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

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

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / services.yml服务:#……AppBundle \树枝\ MyTwigExtension:标签:(twig.extension)

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

你仍然可以手动配置服务如果你需要。

公共和私人服务

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

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / services.yml服务:# * *文件默认配置服务_defaults:#……公众:

这是什么意思?当一个服务公众,你不能访问它直接从容器:

1 2 3 4 5 6 7 8 9
使用AppBundle\服务\MessageGenerator;公共函数newAction(MessageGenerator美元messageGenerator){/ /类型提示它作为参数工作/ /但直接从容器访问它不工作美元- >容器- >get (MessageGenerator::类);}

通常,这是好的:有更好的方法来访问服务。但是,如果你需要你的服务,覆盖该设置:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7
# app / config / services.yml服务:#……同样的代码#显式配置服务AppBundle \服务\ MessageGenerator:公众:真正的

进口很多服务与资源

您已经看到,你可以导入很多服务使用资源关键。例如,默认Symfony的配置包含:欧宝娱乐app下载地址

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# app / config / services.yml服务:#……和以前一样#类的名称空间前缀(\)必须结束AppBundle \:#创建服务的所有类中找到这个目录……资源:“. . / . . / src / AppBundle / *’#……除了类位于这些目录排除:“. . / . . / src / AppBundle /{实体,库}’#上面这些都是进口的,但是我们想要添加标签AppBundle \ \控制器:资源:“. . / . . / src / AppBundle /控制器”#一些配置应用到这些服务标签:(“controller.service_arguments”)

提示

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

这可以用来快速提供许多类作为服务和应用一些默认配置。的id每个服务的完全限定类名。你可以覆盖任何服务进口通过其id(类名)下面(例如看到服务容器)。如果你覆盖服务,没有一个选项(如。公共)是继承了进口(但覆盖服务还是继承_defaults)。

你也可以排除特定的路径。这是可选的,但是会稍微提高性能dev环境:排除路径不跟踪,所以修改它们不会导致容器被重建。

请注意

等等,这是否意味着每一个src / AppBundle注册为服务吗?甚至模型或实体类?事实上,没有。只要你有公众:假在你的_defaults下键(或者您可以添加特定的进口),所有的进口服务私人。谢谢,所有类src / AppBundle这是明确作为服务将自动删除最后的容器。在现实中,导入仅仅意味着所有可用类”使用作为服务“无需手动配置。

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

3.4

名称空间YAML的选项配置是在Symfony 3.4中引入的。欧宝娱乐app下载地址

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

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / services.yml服务:AppBundle域\ \:资源:“. . / . . / src / AppBundleDomain / *’#……

为了有多个定义,添加名称空间选择和使用任何独特的字符串作为每个服务配置的关键:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13
# app / config / services.yml服务:command_handlers:名称空间:应用程序域\ \资源:“. . / . . / src /域/ * / CommandHandler '标签:(command_handler)event_subscribers:名称空间:应用程序域\ \资源:“. . / . . / src /域/ * / EventSubscriber '标签:(event_subscriber)#……

显式配置服务和参数

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