PHP服务容器控制反转,PHP的容器 -- 依赖注入(DI) 和 控制反转(IoC)

PHP的容器 – 依赖注入(DI) 和 控制反转(IoC)

DI - Dependency Injection 依赖注入

IoC - Inversion of Control 控制反转

依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。

依赖注入是从应用程序的角度在描述,可以把依赖注入,即:应用程序依赖容器创建并注入它所需要的外部资源;

而控制反转是从容器的角度在描述,即:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

实现一个容器//根据我们的上面的分析,容器至少需要俩个操作,分别是将类绑定到容器中以及将类从容器中取出的操作

class Container

{

//容器类列表

public static $generator_list = [];

// 绑定类到容器中

public static function bind($class_name, $generator)

{

if (is_callable($generator)) {

self::$generator_list[$class_name] = $generator;

} else {

throw new Exception('对象生成器不是可以调用的类型');

}

}

// 生成类对象

public static function make($class_name, $params = [])

{

if (! isset(self::$generator_list[$class_name])) {

throw new Exception($class_name.'类没有被绑定注册');

}

return call_user_func_array(self::$generator_list[$class_name], $params);

}

}

使用容器//我们先看一下bind()函数,该函数对应上面说到的绑定操作,就是将一个类放到$generator_list中,仔细看一下,你会发现,该函数并不是把一个类或者一个对象直接传递进去,而是传入了两个参数,一个是参数的名字,一个是生成器。

//生成器说白了就是一个函数,这个函数是用来负责实例化需要绑定的类的。

//说到这里,有同学可能有点疑惑,为什么要这样,为什么不直接传一个对象进去那?

//原因是类的实例化的过程是需要传递参数的,传递一个生成器进去,我们在实例化这个类的时候就可以修改参数了。

//下面就是一个绑定示例,大家可以看一下。

Container::bind("A",function($param){

return A($param);

})

self::$generator_list["A"] = function($param){

return A($param);

};

//这样,我们的绑定操作基本就说完了,下面看make()函数。之前也已经提到过了,make()函数就是将所需要的对象从这个容器中取出来。该函数也需要传递两个参数进去,一个是class_name也就是需要取出的类的名称,一个是params,也就是实例化对象的时候需要传递的参数。

//下面的一行代码是整个函数的关键所在:

call_user_func_array(self::$generator_list[$class_name], $params);

self::$generator_list[$class_name]对应的是类的生成器,$params对应的是类实例化所需要的参数,

//call_user_func_array()该函数是PHP的内置函数,通过该函数我们可以执行self::$generator_list[$class_name]对应的是类的生成器函数,这样我们也就是完成了所需类的实例化。(ps:对call_user_func_array()函数不清楚的同学可以先去看一下手册)

测试一下//将类A的生成器函数(匿名函数/闭包)绑定到容器中

Container::bind('A', function($name='') {

return new A($title);

});

//在容器类中获取类A的对象

$Obj = Container::make('A', ['aaa']);

//打印出得到的这个对象

var_dump($Obj);

//打印结果如下:

object(A)#2 (1) {

["name"]=>

string(4) "aaa"

}

//我们在打印出self::$generator_list中的数据看一下:

array(1) {

["A"]=>

object(Closure)#1 (1) {

["parameter"]=>

array(1) {

["$name"]=>

string(10) ""

}

}

}

怎么样,看到上面打印出来的节后是不是就清楚一些了那…上面我们分析了一下容器类的具体的执行方式,上面的代码比较的简单,也灭有涉及到类相互依赖的问题,相比大家肯定想看一下类相互依赖的时候,容器类是怎么为我们解决依赖的,我们下面就写一个例子再分析一下,其实容器的代码我们基本不需要在动了。

//最开始的我们就举了一个B类依赖于A类的例子,现在我们继续使用这个例子来说明一下

//绑定A类到容器中

Container::bind('A', function($name='') {

return new A($title);

});

//绑定B类到容器中

Container::bind('B', function($module,$params=[]) {

return new B(Container::make($module,$params));

});

//上面B类的绑定方式大家可能觉得有点怪,这是因为B类依赖于A类,所以我们在B类的生成器对象中(匿名函数)中需要得到A类的实例传参给B,

//怎么获取A类的实例那,简单,因为A类也存在于容器中,所以我们直接调用make()函数就可以获取A类的实例对象了,

//但是在实例化A类的时候,构造函数可能需要参数,为了能够得到这些参数,我们就需要在B类的生成器对象中将这些参数传递进来。

//下面我们调用一下B类

$Obj= Container::make('B', ['A', ['aaa']]);

//上面我们就获取到了B类的实例化的对象了,是不是很简单,有兴趣的同学可以将上面的结果打印出来看一下。

//我们再分析一下上面的步骤,想要获取B类的实例化对象,直接通过make()进行获取,

//因为B依赖于A,所以需要传递A到生成器函数中,但是A有需要其他的参数,所以我们还需要继续传递其他参数进去,所以参数就是一个二维数组

//上面对参数有疑问的同学可以按照上面的流程分析一遍,就清楚了

Tips

想要实现容器的自动依赖注入,需要使用反射,通过反射,获取类构造函数所需的参数,分析出所依赖的类,然后在容器中获取其所依赖的类,其实就是一层一层的找需要什么,需要什么就在容器中找什么,找到了就作为参数传递过去,这样就实现了自动注入解决了依赖的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值