- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
谈谈php里的IOC控制反转,DI依赖注入
理论
发现问题
在深入细节之前,需要确保我们理解IOC控制反转和DI依赖注入是什么,能够解决什么问题,这些在维基百科中有非常清晰的说明。
控制反转(Inversion of Control,缩写为IoC):是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
依赖注入(Dependency Injection,简称DI):DI是IOC的一种实现,表现为:在类A的实例创建过程中即创建了依赖的B对象,通过类型或名称来判断将不同的对象注入到不同的属性中。
依赖查找(Dependency Lookup,简称DL):DL是IOC的另外一种实现,在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key等信息来确定获取对象
依赖注入与依赖查找是控制反转的2种实现方式,后者很少见,我们主要研究依赖注入。
如果此前没有接触过这些概念,可能还是过于抽象不容易理解,但是下面这个场景你应该是见过的:
因为大多数应用程序都是由两个或是更多的类通过彼此的合作来实现业务逻辑,这使得每个对象都需要获取与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么这将导致代码高度耦合并且难以维护和调试。
也就是说:Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象,这就导致如果A想将B替换为一个更优的实现版本B+时,需要修改代码显式的new一个B+对象。
解决这个问题的传统做法一般是为B和B+提取一个InterfaceOfB接口,然后让class A只依赖InterfaceOfB,最终由A类的调用方决定传入B还是B+对象,修改调用方代码和修改类A代码对我们来说并没有本质的改变,那是否有更好的方式呢?
解决思路
终于,懒惰的程序员对这种代码开发方式感到厌烦:因为我们在代码里控制了B类对象的生成,从而导致代码耦合,即便A类依赖InterfaceOfB,还是要在程序某处写死new B()或者new B+()这样的代码,怎么破解?
答案是:将B类对象的生成交给一个独立的对象生成器来负责,那么A类只需要依赖这个对象生成器,而至于到底是生成B还是B+对象,则是对象生成器内部的行为,这样就将A和B解耦开了,这就是所谓的控制反转,即将控制权交给了对象生成器。
这么简单的将问题抛给对象生成器可不行,因为对象生成器还要面临new B还是new B+的硬编码问题,因此必须赋予对象生成器一个超能力:
在对象生成器的配置文件中进行这样的描述:{InterfaceOfB : Class B+},表示InterfaceOfB接口应该实例化B+对象。
A类构造函数有一个InterfaceOfB的入参,例如:function __construct(InterfaceOfB obj)。
调用对象生成器(DI)获取A类对象,DI-get(class A)。对象生成器会利用反射分析class A的构造函数,发现InterfaceOfB参数后根据此前配置文件描述,new B+()对象传入到A的构造函数,从而生成A对象。
总结上述流程就是:对象生成器通过反射机制分析A类的构造函数依赖,并根据配置中的关系生成依赖的对象实例传入给构造函数,最终完成A类对象的创建。
上面的过程就是依赖注入主要实现方式了,对象生成器我们通常成为DI Container,也就是依赖注入容器。
需要注意的是:B或者B+的构造函数可以会依赖InterfaceOfC,因此整个依赖关系的分析是递归的。
实践
上面在谈DI依赖注入的时候,我们非常清楚的了解到 DI会根据构造函数进行依赖分析,但是很容易忽视{InterfaceOfB : Class B+}这个信息的来源。如果DI不知道这个信息,那么在分析构造函数时是不可能知道接口InterfaceOfB应该对应什么对象的,这个信息在DI实现中一般是通过set方法主动设置到DI容器的依赖关系中的,当然这个信息的存储介质可以是配置文件或者硬编码传入。
下面拿PHP的Yii2.0框架为例,看看它实现DI时的核心思路是什么,不会讲的太细,但上面提到的思路和概念都会有所体现。
set设置类定义
public function set($class, $definition = [], array $params = [])
{
$this-_definitions[$class] = $this-normalizeDefinition($class, $definition);
$this-_params[$class] = $params;
unset($this
文档评论(0)