名词解释
官方解释:
IOC - 控制反转
DI - 依赖注入
通俗举例:
小明以前很穷,风餐露宿,居无定所。现在发财了,自己也想拥有属于自己的房子,这个时候小明想,要不回老家盖一栋房子,一来可以住,二来可以光宗耀祖,这个时候,小明需要自己去打造一栋房子;后来小明又想,为何不在城市里直接买套房呢,生活更加丰富多彩也方便。于是,小明就找了房产中介(IOC容器)买了房子(依赖注入),最终小明很快就住上了属于自己的房子,开心快乐极了。。。
小明 依赖 房子,小明从自己盖房子(自己“控制”房子)到找中介买房子(让中介“控制”房子),这就叫做***控制反转***,也就是IOC;而房产中介根据小明的需求,直接把房子提供给小明(当然小明付钱了),这就叫做*** 依赖注入***,也就是DI。
当然,这个房子并不是房产中介建设的,而是开发商建设的,这个开发商就是***服务提供者***。
三十年后,小明的这套房子格局跟不上时代了,住得不舒服,想改造/重新装修房子,但是时间成本太高了,于是,小明又找房产中介买了房子,小明又很快住上新房子了。。。这也体现了面向对象中类的单一职责原则。
目的
采用IOC思想和DI设计模式,主要目的是:解耦
开车式:异地恋。就算中间隔着一个距离,但也不影响真心的相爱着。
原生代码实现
传统写法
以上代码输出
采用IOC和DI的思想来实现
以上程序输出
对IOC和DI的本质分析
从上面的代码,我们看到,房产中介作为IOC,其实本质就是数组(可以是一维数组,也可以是多维数组)。
其实,在laravel框架中,
Container
对象中的属性$bindings
、$resolved
、$instances
、$aliases
、$abstractAliases
其实也是从不同维度来管理注册到容器中的对象的。上面的例子中,如果从业务逻辑角度来讲,无非就是购房者要买房,主要的类有:购房者、商品房。
如果按照传统代码来实现,那么购房者对象对商品房对象的依赖是***强依赖***,因为在购房者类中需要
new 商品房()
而在采用IOC和DI的思想来实现的话,增加了房产中介对象这个IOC容器,商品房首先在房产中介那边进行一下预售登记,购房者也在房产中介那边进行一下意向登记,购房者对象需要依赖商品房对象,采用依赖注入,即:让房产中介直接把实例化后到商品房对象注入到购房者对象,购房者对象无需关注怎么实例化,只管拿过来用就行。
Laravel框架IOC核心源码——绑定
我们来简单看下Laravel框架的核心容器的绑定是怎么实现的?
以下代码都是在Illuminate\Container\Container类中
- 通过instance方法绑定
使用该方法注册绑定到容器中的对象实例是共享的。
- bind方法
如何使用bind方法来将对象注册绑定到容器中呢?如下,bind方法是将闭包绑定到容器当中
同样,bind方法会先删除旧的实例,然后再新的实例放入闭包中,再绑定到容器中。如果第二个参数不是闭包,会通过getClosure方法将类名封装到闭包中,然后在闭包中通过make方法或build方法解析绑定的类。绑定时会将闭包和是否是shared放入$this->bind[]数组中,解析时调用。
- singleton方法
从官方的代码可以看出,singleton方法,最终还是调用了$this->bind()方法,只是通过singleton()方法绑定到容器的对象只会被解析一次,之后的调用都返回相同的实例,这就是所谓的单例。
Laravel框架IOC核心源码——解析
看源码
从上面的第三段代码build()方法中可以看出,解析时,如果绑定注册的是闭包函数,那么就是直接返回闭包函数的执行,关键代码如下
如果绑定注册的是类名,那么就利用php的反射(ReflectionClass)来实例化对象,并返回给调用者。bind()方法剩下的代码干的就是这个工作。
最后,在resolve()方法中的
代表已经解析成功了。