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

前言

上章了解了服务容器绑定篇,本章介绍通过服务容器解析实例

正文

在Laravel的服务容器中提供了两种用于获取服务容器中实例的方法
make及resolve

make

make在内部是直接调用了resolve,但因为使用容器是大多是使用Application类来进行make的所以会先执行Application类的make,再调用到Container中的make

Application:

public function make($abstract, array $parameters = [])
{
    //获取别名,如果未配置则原样返回
    $abstract = $this->getAlias($abstract);
    //判断是否有延迟服务且未经过instance绑定
    if ($this->isDeferredService($abstract) && ! isset($this->instances[$abstract])) {
        //加载延迟服务提供程序
        $this->loadDeferredProvider($abstract);
    }
    return parent::make($abstract, $parameters);
}

Container:

public function make($abstract, array $parameters = [])
{
    return $this->resolve($abstract, $parameters);
}

resolve

protected function resolve($abstract, $parameters = [], $raiseEvents = true)
{
    //getAlias方法会假定$abstract是绑定的别名,从$aliases找到映 射的真实类型名
    //如果没有映射则$abstract即为真实类型名,将$abstract原样返回
    $abstract = $this->getAlias($abstract);

    //获取给定抽象的上下文具体绑定。
    $needsContextualBuild = ! empty($parameters) || ! is_null(
        $this->getContextualConcrete($abstract)
    );

    // 如果服务是通过instance()方式绑定的,就直接解析返回绑定的service
    if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
        return $this->instances[$abstract];
    }

    $this->with[] = $parameters;
    //获取绑定时存入的闭包
    $concrete = $this->getConcrete($abstract);

    //isBuildable方法:$concrete === $abstract || $concrete instanceof Closure
    if ($this->isBuildable($concrete, $abstract)) {
        //直接构建出实例,如果是闭包就返回闭包,如果不是就通过反射类获取出实例返回
        $object = $this->build($concrete);
    } else {
        //如果时接口实现这种绑定方式,通过接口拿到实现后需要再make一次才能
        $object = $this->make($concrete);
    }

    //获取扩展程序
    foreach ($this->getExtenders($abstract) as $extender) {
        $object = $extender($object, $this);
    }

    //如果服务是以singleton方式注册进来的则,把构建好的服务对象放到 $instances里,
    // 避免下次使用时重新构建
    if ($this->isShared($abstract) && ! $needsContextualBuild) {
        $this->instances[$abstract] = $object;
    }

    if ($raiseEvents) {
        $this->fireResolvingCallbacks($abstract, $object);
    }

    $this->resolved[$abstract] = true;

    array_pop($this->with);

    return $object;
}

build

public function build($concrete)
{
    // 如果是闭包直接执行闭包并返回(对应闭包绑定)
    if ($concrete instanceof Closure) {
        return $concrete($this, $this->getLastParameterOverride());
    }

    // 使用反射ReflectionClass来对实现类进行反射实例操作
    try {
        $reflector = new ReflectionClass($concrete);
    } catch (ReflectionException $e) {
        throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
    }

    // 如果不能实例化,这应该是接口或抽象类,再或者就是构造函数是 private的,进行异常跑出。反之实例化操作
    if (! $reflector->isInstantiable()) {
        return $this->notInstantiable($concrete);
    }

    $this->buildStack[] = $concrete;

    // 获取构造函数
    $constructor = $reflector->getConstructor();

    // 如果构造函数是空,说明没有任何依赖,直接new返回
    if (is_null($constructor)) {
        array_pop($this->buildStack);

        return new $concrete;
    }

    // 获取构造函数的依赖(形参),返回一组ReflectionParameter对象 组成的数组表示每一个参数
    $dependencies = $constructor->getParameters();

    try {
        // 构建构造函数需要的依赖
        $instances = $this->resolveDependencies($dependencies);
    } catch (BindingResolutionException $e) {
        array_pop($this->buildStack);

        throw $e;
    }

    array_pop($this->buildStack);

    //从给出的参数创建一个新的类实例
    return $reflector->newInstanceArgs($instances);
}

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