故事开始
有一天,小明穿越来到了神奇宝贝的世界,这里生活着一群可爱的伊布,小明好奇的用金手指查看了伊布的代码
class Fox{ function evolution(){ } }
从代码可以看出,这些伊布因为作者的原因它无法进化。
于是小明掏出了手术刀开始进行了伊布的修理
class ThunderStone{ public function do(){ echo "进化成了雷属性"; } } class Fox{ function evolution(){ (new ThunderStone())->do(); } } $fox = new Fox(); $fox->evolution(); //输出:进化成了雷属性
这时候,这只伊布就可以进化成雷属性了。
控制反转(IOC)
简单的来说,控制反转可以理解为`将内部耦合的类转移到外部去处理`
这时,小明这段代码有很多的缺陷,因为每次进化不一样的伊布都要不一样的进化石头,目前的代码每次需要进化都得改造其伊布的结构,小明进行了思考,既然伊布的进化是依赖于进化石的,那么是不是可以将其提取到外部去传入,于是小明继续掏出了手术刀。
interface IStore{ public function do(); } class ThunderStone implements IStore{ public function do(){ echo "进化成了雷属性"; } } // class WaterStone implements IStore{ public function do(){ echo "进化成了水属性"; } } class Fox{ public $store; public function __construct(IStore $store) { $this->store = $store; } function evolution(){ $this->store->do(); } } $fox = new Fox(new ThunderStone()); $fox->evolution(); //输出:进化成了雷属性 $fox = new Fox(new WaterStone()); $fox->evolution(); //输出:进化成了水属性
小明在fox类新增了构造函数和一个挂载进化石的属性,将具体的进化石从原先的内部的实体改为了抽象,也就是将依赖转移到了外部去实现,这时候,这个fox类也可以成为一个IOC容器,目的也就达成了。
依赖注入(DI)
小明接着看了看代码,它觉得
$fox = new Fox(new ThunderStone()); $fox->evolution(); //输出:进化成了雷属性 $fox = new Fox(new WaterStone()); $fox->evolution(); //输出:进化成了水属性
这段代码显得特别的不优雅,每次都需要new Fox类和他的依赖类,于是他决定创建一个工具用来自动实例化`(依赖注入)`,再一次掏出了手术刀
interface IStore { public function do(); } class ThunderStone implements IStore { public function do() { echo "进化成了雷属性"; } } // class WaterStone implements IStore { public function do() { echo "进化成了水属性"; } } class Fox { public $store; public function __construct(IStore $store) { $this->store = $store; } function evolution() { $this->store->do(); } } class Di { public $object = []; function bind($class, $param) { if (isset($object)) { return; } $this->object[$class] = $param; } function make($name) { $class = $this->object[$name]; $ref = new ReflectionClass($class); //检查是否可以实例化 if ($ref->isInstantiable()) { //获取构造 $constructor = $ref->getConstructor(); if(!is_null($constructor)){ //获取参数 $p = $constructor->getParameters(); if(empty($p)){ return new $class; } $paramsBox = []; foreach ($p as $item){ $itemClass = $item->getClass(); if(is_null($itemClass)){ $paramsBox[] = null; }else{ //继续去查找绑定的类 $paramsBox[] = $this->make($itemClass->name); } } return $ref->newInstance(...$paramsBox); } return $ref->newInstance(); } else { return null; } } } $di = new Di(); $di->bind(Fox::class,Fox::class); $di->bind(IStore::class, WaterStone::class); $fox = $di->make(Fox::class); $fox->evolution(); //输出:进化成了水属性
小明新增了一个Di,Di里面通过反射去实现了构造函数中类的自动实例化,这样他就只需要通过DI,投入一只伊布和一块进化石,就能产出相应属性的伊布了!
总结
IOC是一种思想,将内部的耦合转移到外部去控制,目的是使其解耦。
而DI是实现这个思想的方式!