依赖注入:A类需要调用B类的功能,所以需要一个B类的对象,一般的写法是在A类中直接实例化B类以获取对象,而依赖注入则是在A类外部实例化B类,然后将B类的对象通过参数注入到A类。

控制反转:将类与类之间的依赖关系管理由内部提到外部进行管理,以此降低程序组件间的耦合度。

ReflectionClass反射类:可用于判断一个类是否可以被实例化、是否有构造函数、获取构造函数的参数、判断参数是否为一个依赖类。

使用反射,我们可以实现从外部判断一个类需要依赖哪些其他类,然后使用程序自动将被依赖类实例化,注入要调用的类。

下面是一个浅显易懂的例子,Controller类需要依赖Db类,所以在构造函数中将Db作为参数,我们在test.php中编写一个maker()函数用于自动创建类的对象,当被依赖的类需要依赖其它类时,maker()函数会被递归调用。


Db.php

<?php
namespace support;

class Db
{
    public function __construct()
    {}
    public function query()
    {}
}

Controller.php

<?php
namespace application;
use support\Db;
class Controller
{
    public $db;
    public function __construct(Db $db, $data = FALSE)
    {
        $this->db = $db;
    }
    public function hello()
    {
        var_dump($this->db);
        echo "Hello World \n";
    }
}

test.php

<?php
namespace test;
use ReflectionClass;
function maker($className){
    // 实例化反射类
    $reflection = new ReflectionClass($className);
    var_dump($reflection);
    
    //判断类是否可以实例化
    $isInstantiable = $reflection->isInstantiable();
    var_dump($isInstantiable);
    if($isInstantiable){   //此类可以实例化才能继续
        //获取构造函数
        $constructor = $reflection->getConstructor();
        var_dump($constructor);
        
        if($constructor){   //需要被注入的类写在构造函数的参数中,以此检测是否需要注入
            //获取构造函数参数
            $params = $constructor->getParameters();
            var_dump($params);
            
            if($params){   //需要被注入的类写在构造函数的参数中,以此检测是否需要注入
                //遍历此函数的参数,判断参数为需要注入的类还是其他值
                $dependencies = [];
                foreach($params as $param){
                    //参数为类时getClass()会返回一个带有类名的对象,不为类时会返回NULL
                    $dependency = $param->getClass();
                    if(is_null($dependency)){
                        //不为类时直接保存到数组占位
                        $dependencies[] = $dependency;
                    }else{
                        //需要注入的参数为类时,递归调用本函数获取需要注入的类的对象
                        $dependencies[] = maker($dependency->name);
                    }
                }
                var_dump($dependencies);
                
                //使用处理好的参数实例化本类,并返回对象
                return $reflection->newInstanceArgs($dependencies);
            }else{   //构造函数无参数表示无需注入,直接实例化返回对象
                return new $className;
            }
        }else{   //无构造函数表示无需注入,直接实例化返回对象
            return new $className;
        }
    }else{   //不可以实例化的返回NULL
        return NULL;
    }
}

include 'Db.php';
include 'Controller.php';

$controller = maker("application\Controller");
$controller -> hello();

结果如下:

res.jpg

标签: none

添加新评论