【Laravel—核心源码解析】服务容器绑定篇

前言

经过对依赖注入、控制反转、服务容器、服务提供者的了解后,对服务容器等有了初步的概念,可以简单的将服务容器理解为一个在框架启动时通过绑定的方式收纳服务的一个数组。这里就将服务容器的操作分为绑定篇及解析篇来进行记录。

正文

在Laravel的服务容器中提供了三种用于绑定的方法,以及两个用于存储服务绑定关系的成员变量
instance方法会将绑定关系存在instances中
bind和singleton则将绑定关系存在bindings中

instance

将现有实例注册到容器中,简单说就是直接绑定已有的实例

//调用范例
$this->instance('app', $this);

public function instance($abstract, $instance)
{
    //移除之前注册过的别名
    $this->removeAbstractAlias($abstract);

    //获取是否有过绑定,主要是对成员变量bindings,instances,aliases进行isset判断
    $isBound = $this->bound($abstract);

    //移除标示对应的别名
    unset($this->aliases[$abstract]);

    //以传入的$abstract为键,实例$instance为值存入成员变量instances中  
    $this->instances[$abstract] = $instance;

    //判断未经过绑定
    if ($isBound) {
        //rebound主要做的是获取当前标示($abstract)配置的回调进行执行
        $this->rebound($abstract);
    }

    return $instance;
}
protected function rebound($abstract)
{
    //解析出实例,具体解析会再后面的解析篇进行解读
    $instance = $this->make($abstract);

    //获取成员变量reboundCallbacks中是否存在为当前标示($abstract)配置的回调
    //有的话则进行调用
    //这里的回调一般都是在服务提供者内部调用容器的rebinding方法进行配置的
    foreach ($this->getReboundCallbacks($abstract) as $callback) {
        call_user_func($callback, $this, $instance);
    }
}

bind

向容器注册绑定,一般会以闭包的形式进行绑定,也有的会以命名空间+类名的形式进行绑定,再bind方法内部再通过命名空间+类名生成闭包

//调用范例
$this->bind('redis', function(){
   return new Redis();
});
public function bind($abstract, $concrete = null, $shared = false)
{
    //删除所有旧的实例和别名
    $this->dropStaleInstances($abstract);

    if (is_null($concrete)) {
        $concrete = $abstract;
    }

    //如果$concrete传的不是闭包,则在这里为其生成concrete闭包
    if (! $concrete instanceof Closure) {
        $concrete = $this->getClosure($abstract, $concrete);
    }

    //以 $abstract 为键,$concrete 和 $shared 合并成的数组为值, 赋值到 bindings 属性中
    $this->bindings[$abstract] = compact('concrete', 'shared');

    //判断 $abstract 标示是否存在与成员变量instances(通过instance进行绑定)
    //和resolved(当被解析过后resolved中会存$abstract => true)中
    //简单说就是满足上面其中之一后就说明这个绑定的实例已经经过实例化了
    if ($this->resolved($abstract)) {
        //rebound主要做的是获取当前标示($abstract)配置的回调进行执行
        $this->rebound($abstract);
    }
}
//获取闭包
protected function getClosure($abstract, $concrete)
{
    //闭包内的代码只有调用是才会执行
    return function ($container, $parameters = []) use ($abstract, $concrete) {
        //值相同的时候通过反射类进行实例获取
        if ($abstract == $concrete) {
            return $container->build($concrete);
        }
        //如果不相同则会根据$concrete再次进行解析
        return $container->resolve(
            $concrete, $parameters, $raiseEvents = false
        );
    };
}

singleton

在容器中注册共享绑定
该方法其实就是在内部调用了bind,再调用时将第三个参数写死为true,以单例的方式进行绑定

//调用范例
$this->singleton('redis', function(){
   return new Redis();
});
public function singleton($abstract, $concrete = null)
{
    $this->bind($abstract, $concrete, true);
}

END

你可能感兴趣的:(【Laravel—核心源码解析】服务容器绑定篇)