Symfonyob娱乐下载 3.3新增功能:Getter注入
警告:这篇文章是关于一个不受支持的Symfony版本。ob娱乐下载有些信息可能已经过时了。阅读最新的Symfony文档ob娱乐下载.
提供的
尼古拉斯Grekas
在# 20973.
警告:这个特性在Symfony 3.3发布之前就被恢复了,所以没有稳定的Symfony版本支持它。ob娱乐下载
作为我们的一部分实验特征程序在Symfob娱乐下载ony 3.3中,我们添加了一个新特性叫做吸气剂注入.这是用于依赖注入的常用机制的总和,并且不替换它们中的任何一个。相反,它提供了一种适合某些特定用例的附加方法。
Getter注入允许依赖注入容器利用提供符合以下要求的基于继承的扩展点的类:无参数且无副作用的公共或受保护方法。
在了解Symfony及其供应商时发现的一些例子:ob娱乐下载
内核:getRootDir / CacheDir LogDir ()
在HttpKernelSessionListener: getSession ()
在HttpKernel中AbstractBaseFactory: getGenerator ()
在ProxyManager
这只是在Symfony核心和其他地方应用这种开/闭原则的所有类中的一个小子集。ob娱乐下载如示例所示,这既适用于对象注入(服务),也适用于值注入(参数)。
Getter注入是一种通过简单的DI配置将这些类转换为DI候选的方法。在Yaml中,以' SessionListener::getSession() '为例,它看起来像:
1 2 3 4
服务:SessionListener:getter方法:getSession:“@ session”
在实践中,这告诉Symfony依赖注入容器创建一个匿名继ob娱乐下载承代理类,就像这样:
12 3 4 5 6 7 8 9 10 11 12 13
$sessionListener=新类(美元)容器)扩展SessionListener{私人$容器;函数__construct(ContainerInterface$容器){$这->容器=$容器;}公共函数getSession(){返回$这->容器->get (“会话”);}};
使用getter注入的优点
考虑getter注入设计的类与其他IoC策略相比有几个优势:
- 使用继承使它们免于与任何框架/DIC的耦合(而不是注入容器);
- 它使得注入的依赖是不可变的(与setter/属性注入相反);
- 通过要求总是使用getter在内部获取一些依赖项,它允许所述依赖项的惰性实例化(相对于构造函数/setter/属性注入);
- 它不会污染构造函数,这是为可扩展性而设计的类的一个优势(与setter/属性注入相同,而与构造函数注入相反);
- 它很好地使用了基于trait的组合,每个trait提供了一组新的开放getter(同样的pro用于setter/属性注入-与构造函数注入相反);
- 它使依赖关系显式(而不是注入容器);
- 它允许使用抽象getter声明强制依赖项;
- 它通过提供返回的默认getter来允许具有可选的依赖项
零
或者一个默认的实现(例如aNullLogger
); - 它允许在使用基类提供的某些特性子集(通常是控制器或命令)时有条件地报告缺失的依赖项——当这种情况发生时抛出有用的异常消息;
- 利用注入点所需的代理很容易编写(参见示例)或生成;
- 当注入的依赖项改变自己时,代理不需要改变(与处理惰性时使用装饰器相反);
- 它在使用注入依赖时不会增加性能开销(与处理惰性时使用装饰器相反);
- 当使用匿名或生成的代理类时,它不会创建任何新类型来提示,因此没有继承问题。
使用getter注入的缺点
- 它需要编写一个继承代理,因此在连接或测试这些类时比其他注入策略增加了更多的样板文件;
- 按照设计,它既不能与最终类一起工作,也不能与私有方法一起工作;
- 由于PHP(与其他语言不同)不提供任何在运行时创建代理的方法,因此它需要手工编写代码、转储容器或使用
eval ()
用于基于运行时的DICs; - 当惰性是目标时,它将惰性责任交给依赖的调用端(与使用修饰时的被调用端相反)——因此,只有当惰性是对getter注入开放的类的核心业务的一部分时,才应该使用它;
- 它增加了间接性,从而使调试更加困难(为什么这门课很有趣?,"哦,这个惰性依赖的初始化在那个时候失败了");
- 当继承代理提供惰性时,它可以在PHP对象图中创建循环依赖项,在某些时候需要进行垃圾收集;
- 如果没有满足无副作用的要求,就会导致bug——当不使用抽象getter时,这个要求在技术上很难执行(需要静态代码分析)。
讨论
“吸气剂注入”的引入是有争议的,它产生了积极和消极的反馈。我试着在上面的列表中总结所有理性的论点,正反两方面。
在解决了这些问题后,我希望随着时间的推移,“惊喜效应”会消失,并只对getter注入进行技术价值评估。我个人的观点是,它以其独特的利弊平衡填补了一些漏洞,因此值得成为开发人员工具链的一部分,并得到Symfony容器的支持。ob娱乐下载
Symfony核心中预想的用例ob娱乐下载
该特性的目标是首先用于特定于框架的需求。现在的目标是提供解耦的可组合的基本控制器特性。看到Pull request 18193这个话题的下一步可能是什么。
常见问题解答
使用典型的依赖注入,如果需要,我可以手动连接我的依赖项。我如何对这样的类做同样的事情?
通过使用例如匿名类:
12 3 4 5 6 7 8 9 10 11 12 13 14
$myDep=新DepClass ();$myConsumer=新类(美元)myDep)扩展ConsumerClass{私人$部;公共函数__construct(DepClassInterface$部){$这->部=$部;}受保护的函数getDep():DepClassInterface{返回$这->部;}};
但那是很多样板文件!
是的,这是在“缺点”中列出的。我们用DICs来做无聊的布线-这里也一样。还要注意,在语言的帮助下,这可以简化为以下内容(在php-internals上有关于这方面的讨论,请支持它):
1 2 3 4 5 6 7 8 9
$myDep=新DepClass ();$myConsumer=新类()使用(美元)myDep)扩展ConsumerClass{私人$部=$myDep;受保护的函数getDep():DepClassInterface{返回$这->部;}};
我如何测试这样一个类?
通过使用例如匿名类(见上文)-或一个模拟框架,例如PHPUnit的:
1 2
$消费者=$这->createPartialMock (“ConsumerClass”, (“getDep”]);$消费者->预计($这->任何())->方法(“getDep”)->将($这->returnValue ($myDep));
这不会鼓励不好的做法,让人们打开他们的类来适应getter注入吗?
人们总是会用创造性的方式去做坏事。在这个主题上没有getter注入的具体内容。
既然这是在后台注入容器,难道我们不能直接注入容器吗?
注入容器(或“服务定位器”设计模式)是不好的做法,因为它隐藏了你的类正在使用的依赖:doing容器- >(“foo”)——> doFoo ()
在你的代码中依赖于几个松散强制的假设,即:
- 那
美元的容器
有一个得到
方法,通常由框架的DI组件提供(与它耦合); - 这一
得到
方法的服务名为喷火
(这是与外部配置的耦合); - 那就是
喷火
服务有一个doFoo
方法(也耦合到外部配置)。
如果这些假设中的任何一个不再有效,那么这样的代码就很脆弱:任何错误都可能在代码实际运行之前无法检测到(重构的噩梦)。
Getter注入(就像构造函数/setter注入一样)使你的类没有任何这样的问题:扩展点是显式的,并提示返回类型(你需要PHP 7)。通过使用兼容的DIC,代码会根据你代码中的这些显式声明自动生成。
我还是觉得很内疚
没问题!请记住,这个特性是可选的,您的Symfony应用程序不必使用它。ob娱乐下载
评论
评论截止。
为了确保评论保持相关性,旧帖子将被关闭。
一个很好的例子是Drupal测试系统,我们讨论了使用' $this->容器vs \Drupal::getContainer() ' https://www.drupal.org/node/2066993。
Vlad Riabchenko is a certified Symfony engineer.
Get certified! Online exams available in all countries.
Register Now我认为可以通过php7中方法的返回类型声明或php5中的dockblock来自动装配依赖项。您可以考虑将任何抽象getter函数作为在代理中实现的候选函数。