Symfob娱乐下载ony 3.3 DI容器变化解释(自动装配、_defaults等)

编辑该页面

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

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

Symfob娱乐下载ony 3.3 DI容器变化解释(自动装配、_defaults等)

如果你看一下services.yaml文件在一个新的Symfonyob娱乐下载 3.3或更新的项目中,你会注意到一些大的变化:_defaults,自动装配,可以使用autoconfigure和更多。这些功能的设计自动化配置和使发展更快,不牺牲可预测性,这是非常重要的!另一个目标是使控制器和服务表现更为稳定。在Syob娱乐下载mfony 3.3中,控制器默认服务。

文档已经欧宝官网下载app更新,假设您启用了这些新特性。如果你是一个现有的Symfony用户想了解“ob娱乐下载是什么”和“为什么”背后的这些变化,本文为您服务!

所有更改都是可选的

最重要的是,你可以升级到3.3 Symfony今天ob娱乐下载没有做任何修改应用程序。ob娱乐下载Symfony有严格的向后兼容性的承诺,这意味着它总是安全的跨小版本升级。

所有的新功能可选:他们不是默认启用,所以你需要改变你的配置文件来使用它们。

新的默认服务。yaml文件

理解变化,看看新的默认services.yaml文件(文件的样子在Symfony 4):ob娱乐下载

  • YAML
  • XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日24
#配置/ services.yaml服务:# * *文件默认配置服务_defaults:自动装配:真正的#自动注入依赖在你的服务。可以使用autoconfigure:真正的#自动注册您的服务作为命令,事件订阅者,等等。公众:#允许优化集装箱通过删除未使用的服务;这也意味着#获取服务直接从容器通过$容器- >()是行不通的。#最佳实践是对你的依赖关系明确。#在src /可以使类作为服务#这将创建一个服务每个类的id是完全限定的类名App \:资源:“. . / src / *”排除:“. . / src /{实体、迁移、测试}'#控制器分别进口,以确保服务可以被注入#作为动作参数即使你不扩展任何基本控制器类应用程序控制器\ \:资源:“. . / src /控制器”标签:(“controller.service_arguments”)#添加更多的服务定义显式配置是必要的#请注意,最后总是*取代*之前的定义

这个小的配置包含一个服务配置在Symfony的范式转变。ob娱乐下载

1)服务是自动加载

另请参阅

阅读的文档欧宝官网下载app自动服务加载

第一个大的变化是服务需要一个定义了,感谢以下配置:

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

这意味着每一个类src /可用作为一个服务。和感谢_defaults部分在文件的顶部,所有这些服务autowired的私人(即。公众:假)。

服务id等于类名(如。应用\ \ InvoiceGenerator服务)。Symfony中,您会注意到的另一个更改3.3:我们建议您使用类名作为您的服务id,除ob娱乐下载非你有同一个类的多个服务

但容器是怎样知道我的服务的参数吗?

由于每个服务autowired的,容器能够自动确定大多数参数。但是,你总是可以覆盖服务和手动配置参数你的服务或其他特别之处。

但是,等等,如果我有一些模型(较)在我的类src /目录,这并不意味着他们也会注册为服务?这不是一个问题吗?

其实,这是一个问题。因为所有的新服务私人(由于_defaults),如果任何服务在代码中使用,他们将自动删除编译后的容器。这意味着服务的数量在你的容器应该是相同无论您显式配置每个服务或负载都用这个方法。

好吧,但是我可以排除一些路径知道不包含服务?

是的!的排除关键是一团模式,可用于黑名单路径,要包括为服务。但是,由于未使用的服务是自动从容器中删除,排除并不是那么重要。最大的好处是,这些路径跟踪由容器,因此可能导致容器需要重建将不常在dev环境。

2)默认自动装配:用Type-hint代替服务id

第二个大的变化是,(通过启用自动装配_defaults你注册)为所有服务。这也意味着服务id的现在重要的“类型”(即类或接口的名称)更多的重要的。

例如,在Symfony 3.3之前(这仍ob娱乐下载然是允许的),你可以将一个服务作为参数传递给另一个使用以下配置:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9
#配置/ services.yaml服务:app.invoice_generator:类:应用\ \ InvoiceGenerator服务app.invoice_mailer:类:应用\ \ InvoiceMailer服务参数:- - - - - -“@app.invoice_generator”

通过InvoiceGenerator作为参数InvoiceMailer,您需要指定服务的id作为一个参数:app.invoice_generator。服务标识的是你配置的主要途径。

但是在Symfob娱乐下载ony 3.3中,由于自动装配,所有你需要做的就是type-hint论点InvoiceGenerator:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
/ / src /服务/ InvoiceMailer.php/ /……InvoiceMailer{私人美元发电机;公共函数__construct(InvoiceGenerator美元发电机){美元- >发电机=美元发电机}/ /……}

就是这样!这两个服务自动注册并设置为自动装配。没有任何配置,容器知道通过auto-registered应用\ \ InvoiceGenerator服务作为第一个参数。正如您可以看到的,类型类的,应用\ \ InvoiceGenerator服务——是什么最重要,而不是id。你请求一个实例特定类型的容器会自动将你正确的服务。

这不是魔术吗?它如何知道哪些服务完全递给我吗?如果我有多个服务相同的实例吗?

自动装配系统设计超级可预测的。它首先通过寻找工作的服务id完全与type-hint匹配。这意味着你在什么type-hint映射到服务的完全控制。您甚至可以使用服务别名来获得更多的控制。如果你有多个服务为一个特定的类型,选择应该用于自动装配。自动装配的完整细节逻辑,看到自动定义服务依赖关系(自动装配)

但是,如果我有一个标量(例如字符串)论点吗?它是如何自动装配?

如果你有一个论点一个对象,它不能autowired的。但没关系!ob娱乐下载Symfony会给你一个明确的异常(在接下来的刷新任何页面)告诉你这论点不能autowired的服务。要修复它,你可以手动配置* *,一个参数。这是自动装配的哲学:只有配置你需要的部分。大多数配置自动化。

好的,但是自动装配使应用程序更不稳定。如果你改变一件事或犯错误时,可能会发生意想不到的事情。这不是一个问题吗?

ob娱乐下载Symfony一直重视稳定性、安全性和可预见性。自动装配设计考虑到这一点。具体地说:

  • 如果有连接问题任何参数任何服务,清晰异常的下一个刷新任何页面,即使你不使用该服务页面。这是强大的:它是可以做一个自动装配错误并没有意识到它。
  • 容器决定哪一个服务传递一个明确的方式:它看起来type-hint完全匹配的服务id。它扫描所有服务寻找对象类/接口。

自动装配的目的是自动化配置没有魔法。

3)控制器注册为服务

第三个大的变化是,在一个新的3.3 Symfony项目,你的控制器ob娱乐下载服务:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9
#配置/ services.yaml服务:#……#控制器分别进口,以确保它们是公开的#和有一个标签,允许操作type-hint服务应用程序控制器\ \:资源:“. . / src /控制器”标签:(“controller.service_arguments”)

但是,你甚至可能不会注意到这一点。首先,你的控制器可以仍然扩展相同的基础控制器类或一个新的AbstractController。这意味着您可以访问所有的快捷方式和以前一样。此外,@Route注释和_controller语法(如。应用:默认值:主页)用于路由会自动使用控制器作为服务(只要其服务id匹配它的类名称,它在这种情况下)。看到如何定义控制器作为服务吗为更多的细节。你甚至可以创建调用控制器

换句话说,所有工作都是相同的。你甚至可以将上面的配置添加到您的现有项目没有任何问题:控制器行为与之前相同。但是现在你的控制器是服务,您可以使用依赖项注入和自动装配和其他服务。

使生活更容易,现在可以自动装配参数控制器操作方法,就像你可以与构造函数的服务。例如:

1 2 3 4 5 6 7 8 9
使用Psr\日志\LoggerInterface;InvoiceController扩展控制器{公共函数listInvoices(LoggerInterface美元日志记录器){美元日志记录器- >信息(“一种新的方式来访问服务!”);}}

这是只有可能在一个控制器,控制器必须标记服务controller.service_arguments让它发生。使用这个新特性在整个文档。欧宝官网下载app

一般来说,新的最佳实践是使用普通构造函数依赖注入(或“行动”注入控制器),而不是通过获取公共服务$ this - > get ()(尽管仍工作)。

4)使用autoconfigure着

第四大变化可以使用autoconfigure设置为关键真正的_defaults。多亏了这个,容器会自动标记服务注册在这个文件中。例如,假设您希望创建一个事件订阅者。首先,您创建的类:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/ / src / EventSubscriber / SetHeaderSusbcriber.php/ /……使用ob娱乐下载\组件\EventDispatcher\EventSubscriberInterface;使用ob娱乐下载\组件\HttpKernel\事件\FilterResponseEvent;使用ob娱乐下载\组件\HttpKernel\KernelEvents;SetHeaderSusbcriber实现了EventSubscriberInterface{公共函数onKernelResponse(FilterResponseEvent美元事件){美元事件- >getResponse ()- >- >集(“x ob娱乐下载- symfony - 3.3”,低配置的);}公共静态函数getSubscribedEvents(){返回[KernelEvents::响应= >“onKernelResponse”];}}

太棒了!在Syob娱乐下载mfony 3.2或更低,您现在需要注册这个服务services.yaml并标记kernel.event_subscriber。在Syob娱乐下载mfony 3.3中,你已经完成了!服务自动注册。感谢可以使用autoconfigure,Sob娱乐下载ymfony会自动标签服务,因为它实现了EventSubscriberInterface

那听起来像是魔法——它自动标记我的服务吗?

在这种情况下,您已经创建了一个类实现EventSubscriberInterface并注册为一个服务。这是容器的足够多的知道你想要这个用作事件订阅者:不需要更多的配置。和标签系统自身,Symfony-specific机制。ob娱乐下载当然,你总是可以设置可以使用autoconfigureservices.yaml一个特定的服务,或禁用它。

这是否意味着标签是死了吗?这适用于所有标签吗?

这并适用于所有标签。很多标签要求属性,如事件听众,您还需要指定事件名称和标记方法。Autoconfigure只适用于标签没有任何必需的标记属性,当你阅读的文档功能,它会告诉你是否标记是必需的。你也可以看看扩展类(如。为3.3.0 FrameworkExtension),看看它可以使用autoconfigure。

如果我需要添加一个优先标签?

许多可以使用autoconfigure标签有一个可选的优先级。如果你需要指定一个优先级(或任何其他可选的标记属性),没问题!只是手动配置您的服务并添加标签。你的标签将优先于自动添加的。

5)与_instanceof自动配置

最后一个大的变化_instanceof。它作为一个默认的模板(见定义service-33-default_definition),但仅限于类匹配的服务定义。

这可能是非常有用的,许多服务分享一些标签,不能继承一个抽象的定义:

  • YAML
  • XML
1 2 3 4 5 6 7 8
#配置/ services.yaml服务:#……_instanceof:应用程序域\ \ LoaderInterface:公众:真正的标签:(“app.domain_loader”)

它的性能怎么样

ob娱乐下载Symfony是独一无二的,因为它有一个编译容器。这意味着有没有使用这些特性的运行时性能的影响。这也是为什么自动装配系统可以给你这样明显的错误。

然而,有一些性能的影响dev环境。最重要的是,你的容器可能会重建往往当你修改服务类。这是因为它需要重建一个服务,当你添加一个新的参数或添加一个接口类,应该可以使用autoconfigure。

在非常大的项目中,这可能是一个问题。如果是,你可以选择使用自动装配。如果你认为重建缓存系统可以更聪明在一些情况下,请打开一个问题!

3.3升级到新的Symfony的配置ob娱乐下载

准备升级现有的项目吗?太棒了!假设你有以下配置:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#配置/ services.yaml服务:app.github_notifier:类:应用\ \ GitHubNotifier服务参数:- - - - - -“@app.api_client_github”markdown_transformer:类:应用\ \ MarkdownTransformer服务app.api_client_github:类:应用\ \ ApiClient服务参数:- - - - - -“https://api.github.com”app.api_client_sl_connect:类:应用\ \ ApiClient服务参数:- - - - - -“https://connect.sensiolabs.com/api”

它是可选的,但是我们这升级到新的Symfony 3.3配置循序渐进,ob娱乐下载没有打破我们的应用程序。

步骤1):增加_defaults

首先,添加一个_defaults部分与自动装配可以使用autoconfigure

1 2 3 4 5 6 7
#配置/ services.yaml服务:+ _defaults:+自动装配:真+ autoconfigure:真#……

这一步很简单:你已经显式地配置你的所有服务。所以,自动装配什么也不做。你也已经标记你的服务,所以可以使用autoconfigure也不会改变任何现有的服务。

您还没有添加公众:假然而。将会在一分钟。

步骤2)使用类的服务id

现在,机器名称,如服务id。app.github_notifier。工作与新配置系统,您的服务id应该是类名,除非你有相同服务的多个实例。

首先,更新服务id类名:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#配置/ services.yaml服务:#……- app.github_notifier:-类:应用\ \ GitHubNotifier服务+应用服务\ \ GitHubNotifier:参数:——“@app.api_client_github”- markdown_transformer:-类:应用\ \ MarkdownTransformer服务+应用服务\ \ MarkdownTransformer: ~#保持这些id,因为每个类有多个实例app.api_client_github: #……app.api_client_sl_connect: #……

谨慎

服务与全球PHP类(即不使用PHP名称空间)必须保持参数。例如,当使用旧的树枝类(如。Twig_Extensions_Extension_Intl而不是树枝\ \ IntlExtension扩展),您可以重新定义服务Twig_Extensions_Extension_Intl: ~你必须保持原来的参数。

谨慎

如果处理的服务编译器通过,你可能会面临“你要求一个不存在的服务”错误。为了摆脱这一点,确保编译器通过使用findDefinition ()而不是getDefinition ()。后者不会考虑别名当查找服务。而且总是推荐检查定义存在使用有()函数。

但是,这种变化将会打破我们的应用程序!旧服务id(例如。app.github_notifier)已不复存在。解决这个问题最简单的方法是找到所有你的旧服务id和更新他们的新类id:app.github_notifier应用\ \ GitHubNotifier服务

在大型项目中,有一个更好的办法:创建遗留的别名,老id映射到新的id。创建一个新的legacy_aliases.yml文件:

1 2 3 4 5 6 7 8 9
# app / config / legacy_aliases.yml服务:_defaults:公众:真正的#别名,这样仍然可以访问旧服务id#删除这些如果/当你不直接抓取这些#从容器中通过$容器- >获得()app.github_notifier:“@App \ \ GitHubNotifier服务”markdown_transformer:“@App \ \ MarkdownTransformer服务”

然后导入的顶部services.yaml:

1 2 3 4 5
#配置/ services.yaml+进口:+ -{资源:legacy_aliases。yml}#……

就是这样!旧服务id仍然工作。后,清理步骤(见下图),您可以删除这些从你的应用程序。

步骤3)让私人服务

现在您已经准备好默认所有服务私人:

1 2 3 4 5 6 7 8
#配置/ services.yaml#……服务:_defaults:自动装配:真的可以使用autoconfigure:真的+公共:假

由于这一点,任何服务中创建这个文件不能直接从容器中取出。但是,因为老服务id的是在一个单独的文件(别名legacy_aliases.yml),这些还公开。这确保应用程序工作。

如果你做改变你的一些服务的id(因为有同一个类的多个实例),您可能需要让公众:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#配置/ services.yaml#……服务:#……app.api_client_github: #……+ #删除如果/当你不取直接从容器通过+ # $容器- >获得()+公共:真app.api_client_sl_connect: #……+公共:真

这是为了保证应用程序不休息。如果你不抓取这些服务直接从容器中,这并不是必要的。在一分钟内,你就会干净。

步骤4)Auto-registering服务

你现在准备好所有服务自动注册src /(和/或任何其他目录/包):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#配置/ services.yaml服务:_defaults:#……+应用\:+资源:“. . / src / *”+排除:“. . / src /{实体、迁移、测试}'++应用\ \控制器:+资源:“. . / src /控制器”+标签(“controller.service_arguments”):#……

就是这样!事实上,你已经重写和重新配置您正在使用的所有服务(应用\ \ GitHubNotifier服务应用\ \ MarkdownTransformer服务)。但是现在,你不需要手动注册的未来服务。

再一次,有一个额外的并发症,如果你有同一个类的多个服务:

1 2 3 4 5 6 7 8 9 10 11 12 13
#配置/ services.yaml服务:#……+ #别名ApiClient下面我们的服务之一+ # app.api_client_github将用于自动装配ApiClient类型提示+应用服务\ \ ApiClient:“@app.api_client_github”app.api_client_github: #……app.api_client_sl_connect: #……

这可以保证如果你试图自动装配ApiClient例如,app.api_client_github就会被使用。如果你有这个,汽车上牌特性将尝试注册一个第三ApiClient服务和使用自动装配(这将会失败,因为类non-autowireable论点)。

步骤5)清理!

确保你的应用程序没有休息,你做了一些额外的工作。现在是时候清理的东西!首先,更新您的应用程序使用旧的服务id(的legacy_aliases.yml)。这意味着更新任何服务参数(如。@app.github_notifier@App \ \ GitHubNotifier服务)和更新你的代码不直接从容器获取该服务。例如:

1 2 3 4 5 6 7 8 9
公共函数指数()+公共函数指数(GitHubNotifier GitHubNotifier美元,MarkdownTransformer MarkdownTransformer美元){/ /获取服务的老方法- $ githubNotifier = $ this - >容器- > (“app.github_notifier”);- $ markdownTransformer = $ this - >容器- > (“markdown_transformer”);/ /……}

一旦你这样做,你可以删除legacy_aliases.yml和删除其进口。你应该做同样的事情对于你公开的任何服务,app.api_client_githubapp.api_client_sl_connect。一旦你不抓取这些直接从容器,你可以删除公众:真国旗:

1 2 3 4 5 6 7 8 9 10 11
#配置/ services.yaml服务:#……app.api_client_github: #……——公众:真app.api_client_sl_connect: #……——公众:真

最后,您可以选择删除任何服务services.yaml可以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 29 30 31 32 33
服务:_defaults:自动装配:真正的可以使用autoconfigure:真正的公众:App \:资源:“. . / src / *”排除:“. . / src /{实体、迁移、测试}'应用程序控制器\ \:资源:“. . / src /控制器”标签:(“controller.service_arguments”)应用程序服务\ \ GitHubNotifier:#这可能被删除,或者我可以一直被明确参数:- - - - - -“@app.api_client_github”#别名ApiClient下面我们的服务之一# app.api_client_github将用于自动装配ApiClient类型提示应用程序服务\ \ ApiClient:“@app.api_client_github”#保持这些id,因为每个类有多个实例app.api_client_github:类:应用\ \ ApiClient服务参数:- - - - - -“https://api.github.com”app.api_client_sl_connect:类:应用\ \ ApiClient服务参数:- - - - - -“https://connect.sensiolabs.com/api”

现在,您可以利用新特性。

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