Code前端首页关于Code前端联系我们

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

terry 2年前 (2023-09-24) 阅读数 51 #后端开发

控制器必须使用一个类A,然后newA它,然后调用该类的对象。但是这个类实例化的时候,必须要传递一个类B的实例来改造对象,我们必须先创建new B,然后再传递它。这就是类之间的依赖关系。

我们在控制器方法中更新这个类,然后使用它,但是我们发现框架中很多类不需要你实例化,方法中直接有形参可以使用。基本上,框架的底层会更新类,然后将其传递给方法参数,以便您可以直接在方法中使用它。那么方法中原来由new类创建的实例对象在方法外就变成new了,之后再传递。进来吧,从这个方法来看,这是一种反转,也就是控制反转。如果你在方法之外查看它,我不需要你的新方法。我已将新的形式参数传递给该方法。你可以直接使用它,那么这个角度就是依赖注入。事实上,它们基本上是同一件事。

现在我们了解了概念,接下来我们来了解什么是IOC容器和反射。

首先,我们有几个类,它们之间存在依赖关系。看里面的构造方法就知道了。我们需要在控制器方法中使用这个类A,但是上面我们已经知道我们不需要在方法中使用new。太复杂了,更何况A类还有这么多层依赖。所以框架底层帮我们new了然后给我们用(控制反转、依赖注入);

/**
 * @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,然后我们创建一个工厂类,帮助我们实例化方法中的类,然后供我们使用: 如下图,Laravel底层解读:控制反转与依赖注入、IOC容器和反射

创建一个IOC工厂类,在数组中实例化这些类,然后在使用时将其提供给我们(工厂单例模式)。这就是控制反转,有一个专门的ioc类帮助我们实例化对象,并且不需要我们实例化它们,但是上面的代码仍然存在问题。我们的A类存储依赖于B类,而B类又依赖于CD和其他类,所以虽然它帮助我们实例化它,但它仍然需要被重写。中间写依赖(注意上图中没有写,这里添加)。

这是否意味着我们所有的类都具有依赖关系?如果这个工厂类是新的,那么包装框架的人是否必须手动填充每个类的依赖项?

当然不是,这个IOC工厂类会用到PHP的反射。其实反射就是PHP提供的一组API,可以让我们获取类信息。例如,我有一个包含属性、方法、类名、注释和静态的类。我们采用反射的方式来传递。对于这个类的名称,可以通过调用response的get方法来获取对应的属性或者成员方法、构造函数,甚至注释。

也就是我们的IOC工厂类帮助我们实例化框架底层的类。当我们这样做时,我们不必考虑告诉哪个类依赖于哪个类。框架可以调用反射方法来获取对应的类。构造方法,然后得到这个类必须经过哪个类的实例,即知道这个类需要的依赖类。

以下几组方法是反射。直接A。

具体代码如下:

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类来实例化控制器外部的类了(控制反转)。实例化过程使用反射和递归,然后将其传递给方法参数。 (依赖注入),供用户使用。

Lavavel 将 ioc 工厂类称为 IOC 容器。因为类被实例化并存储在变量中,所以变量对应于这些类的容器。只要你掌握了要点,你就可以随心所欲地称呼它。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门