详解Laravel服务容器的绑定与解析(4)

第一步:

$needsContextualBuild = ! empty($parameters) || ! is_null(
  $this->getContextualConcrete($abstract)
);

  该方法主要是区分,解析的对象是否有参数,如果有参数,还需要对参数做进一步的分析,因为传入的参数,也可能是依赖注入的,所以还需要对传入的参数进行解析;这个后面再分析。

第二步:

if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
  return $this->instances[$abstract];
}

  如果是绑定的单例,并且不需要上面的参数依赖。我们就可以直接返回 $this->instances[$abstract]。

第三步:

$concrete = $this->getConcrete($abstract);
...
/**
 * Get the concrete type for a given abstract.
 *
 * @param string $abstract
 * @return mixed  $concrete
 */
protected function getConcrete($abstract)
{
  if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
    return $concrete;
  }
  // If we don't have a registered resolver or concrete for the type, we'll just
  // assume each type is a concrete name and will attempt to resolve it as is
  // since the container should be able to resolve concretes automatically.
  if (isset($this->bindings[$abstract])) {
    return $this->bindings[$abstract]['concrete'];
  }
  return $abstract;
}

  这一步主要是先从绑定的上下文找,是不是可以找到绑定类;如果没有,则再从 $bindings[] 中找关联的实现类;最后还没有找到的话,就直接返回 $abstract 本身。

// We're ready to instantiate an instance of the concrete type registered for
// the binding. This will instantiate the types, as well as resolve any of
// its "nested" dependencies recursively until all have gotten resolved.
if ($this->isBuildable($concrete, $abstract)) {
  $object = $this->build($concrete);
} else {
  $object = $this->make($concrete);
}
...
/**
 * Determine if the given concrete is buildable.
 *
 * @param mixed  $concrete
 * @param string $abstract
 * @return bool
 */
protected function isBuildable($concrete, $abstract)
{
  return $concrete === $abstract || $concrete instanceof Closure;
}

  如果之前找到的 $concrete 返回的是 $abstract 值,或者 $concrete 是个闭包,则执行 $this->build($concrete),否则,表示存在嵌套依赖的情况,则采用递归的方法执行 $this->make($concrete),直到所有的都解析完为止。

$this->build($concrete)


/**
 * Instantiate a concrete instance of the given type.
 *
 * @param string $concrete
 * @return mixed
 *
 * @throws \Illuminate\Contracts\Container\BindingResolutionException
 */
public function build($concrete)
{
  // If the concrete type is actually a Closure, we will just execute it and
  // hand back the results of the functions, which allows functions to be
  // used as resolvers for more fine-tuned resolution of these objects.
  // 如果传入的是闭包,则直接执行闭包函数,返回结果
  if ($concrete instanceof Closure) {
    return $concrete($this, $this->getLastParameterOverride());
  }
  // 利用反射机制,解析该类。
  $reflector = new ReflectionClass($concrete);
  // If the type is not instantiable, the developer is attempting to resolve
  // an abstract type such as an Interface of Abstract Class and there is
  // no binding registered for the abstractions so we need to bail out.
  if (! $reflector->isInstantiable()) {
    return $this->notInstantiable($concrete);
  }
  $this->buildStack[] = $concrete;
  // 获取构造函数
  $constructor = $reflector->getConstructor();
  // If there are no constructors, that means there are no dependencies then
  // we can just resolve the instances of the objects right away, without
  // resolving any other types or dependencies out of these containers.
  // 如果没有构造函数,则表明没有传入参数,也就意味着不需要做对应的上下文依赖解析。
  if (is_null($constructor)) {
    // 将 build 过程的内容 pop,然后直接构造对象输出。
    array_pop($this->buildStack);
    return new $concrete;
  }
  // 获取构造函数的参数
  $dependencies = $constructor->getParameters();
  // Once we have all the constructor's parameters we can create each of the
  // dependency instances and then use the reflection instances to make a
  // new instance of this class, injecting the created dependencies in.
  // 解析出所有上下文依赖对象,带入函数,构造对象输出
  $instances = $this->resolveDependencies(
    $dependencies
  );
  array_pop($this->buildStack);
  return $reflector->newInstanceArgs($instances);
}
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/5049.html