Laravel底层解读:控制反转与依赖注入、IOC容器和反射

2023-01-3019:48:41后端程序开发Comments1,085 views字数 2556阅读模式

控制器中需要使用一个类A,然后newA 它,然后调用这个类的对象,然而这个类实例化时候需要传递B类的实例化对象,我们就需要先去new B 然后传递,这个是类之间的依赖关系。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

我们在控制器方法中new这个类,然后使用它,但是我们发现很多框架中的类,不需要你去实例化,而方法中直接有个形参就可以用。本质上就是框架底层去new 了这个类,然后传递给这个方法形参,所以你在方法里面可以直接用,那么这个原本在方法中new 类创建实例对象,变成了在方法外面new 了 然后传递进来,这个站在这个方法的角度来看,就是一种反转,也就是控制反转,如果站在方法外面来看,我不需要你new 我new好了传递给方法的形参,你直接用就行,那么这个视角,就是依赖注入。其实本质就是一样的东西。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

我们理解了概念之后,我们来理解一下什么是IOC容器和反射。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

首先我们有这么几个类,之间有依赖关系,看里面构造方法可以得知。这个class A 我们需要在控制器方法中使用,但是我们上面已经知道了我们在方法中使用A 不需要自己去new ,太复杂了,何况 A类有那么多层的依赖关系。所以框架底层帮我们new好 然后给我们使用(控制反转、依赖注入);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

/**
 * @author zhaoruiqing
 * @date 2022-
 * @desc 我是类A的注释
 */
class A
{
    //我是构造函数的注释
    public function __construct(B $b)
    {
        $this->b = $b;
    }
    //我是getB的注释
    public function getB()
    {
        $this->b->bMethod();
    }
}
class B
{
    public function __construct(C $c,D $d)
    {
        $this->c = $c;
        $this->d = $d;
    }
    public  function bMethod()
    {
        echo "我是B中的方法bMethod()";
    }
}

class C{
    public function __construct(){

    }
    public function cMethod(){
        echo "我是C中的方法cMethod()";
    }

}

class D{
    public function __construct(){

    }
    public function dMethod(){
        echo "我是D中的方法dMethod()";
    }
}

那么框架中如何,帮我们new A,那我们做一个工厂类,专门帮助我们在方法中实例类,然后给我们使用:如下图文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

Laravel底层解读:控制反转与依赖注入、IOC容器和反射

创建了一个IOC工厂类,实例化这些类村粗到数组中,用的时候,然后给我们(工厂单例模式),这个就是控制反转,有个专门的ioc类帮我们实例对象,不要我们实例化,但是上面的代码仍然有问题,我们这个A类存储依赖B类,B类依赖于CD等等类,所以即便帮我们实例化,也需要在夸号中写上依赖关系,(注意上图没有写,这里补充)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

难道我们所有类存在依赖关系,让这个工厂类,去new ,都要封装框架的人去手动填写每个类的依赖关系吗?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

当然不是,这个IOC工厂类,会用到PHP的一个反射,其实反射就是PHP提供的一组让我们获取类信息的Api,比如,我有一个类,里面有属性、方法、类名、注释、静态的也好,我们通过反射方法,传递这个类的名称,调用响应的获取方法,就可以得到相应的属性或者成员方法、构造方法、甚至注释。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

那也就是说我们IOC工厂类,在框架底层去帮我们实例化类的,时候,不需要认为去告诉哪个类依赖于哪个类,框架可以调用反射方法,去获取相应的类中的构造方法,然后得到这个类需要传递哪个类的实例,也就是知道了这个类所需要的依赖类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

如下几组方法,就是反射。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

 //获取类的反射信息,也就是类的所有信息
        $reflector = new ReflectionClass(类名);
         echo $reflector->getDocComment();  获取类的注释信息

        //获取反射类的构造函数信息
        $constructor = $reflector->getConstructor();
        //获取反射类的构造函数的参数
        $dependencies = $constructor->getParameters();

但是A依赖于B ,B依赖于C C依赖于D 等,这样子可以使用递归反射api,就可以得到最终使用A需要实例化哪些类,直接如何传递。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

具体代码,如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

class Ioc
{
    protected $instances = [];
    public function __construct()
    {
    }
    public function getInstance($abstract){
        //获取类的反射信息,也就是类的所有信息
        $reflector = new ReflectionClass($abstract);
        //  echo $reflector->getDocComment();  获取类的注释信息

        //获取反射类的构造函数信息
        $constructor = $reflector->getConstructor();
        //获取反射类的构造函数的参数
        $dependencies = $constructor->getParameters();

        if(!$dependencies){
            return new $abstract();
        }
        foreach ($dependencies as $dependency) {

            if(!is_null($dependency->getClass())){
                $p[] = $this->make($dependency->getClass()->name);
                //这里$p[0]是C的实例化对象,$p[1]是D的实例化对象
            }
        }
        //创建一个类的新实例,给出的参数将传递到类的构造函数
        return $reflector->newInstanceArgs($p);
    }


    public function make($abstract)
    {
        return $this->getInstance($abstract);
    }
}

$ioc = new Ioc();
$a = $ioc->make('A');
$a->getB();

到这里我们就可以通过IOC这个类去在控制器之外实例化类(控制反转),实例化过程运用了反射和递归,然后传递给方法形参(依赖注入),给用户使用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

Lavavel把ioc这个工厂类叫做IOC容器。因为实例化类之后存储在变量,变量相当于这些类的容器。名字随便怎么叫啦,理解本质就好。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/30570.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/30570.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定