Laravel (5.5.33) 加载过程---make方法(四)
/** * Resolve the given type from the container. * * @param string $abstract * @return mixed */ public function make($abstract) { return $this->resolve($abstract); }
make函数的大致执行流程
其中resolve源码的说明
/** * Resolve the given type from the container. * * @param string $abstract * @param array $parameters * @return mixed */ protected function resolve($abstract, $parameters = []) { /** * 别名转换 */ $abstract = $this->getAlias($abstract); /** * 如果参数不为空 或者给定的别名存在存在contextual中 则$needsContextualBuild 为true */ $needsContextualBuild = ! empty($parameters) || ! is_null( $this->getContextualConcrete($abstract) ); // If an instance of the type is currently being managed as a singleton we'll // just return an existing instance instead of instantiating new instances // so the developer can keep using the same objects instance every time. /** * 如果是给定的别名是容器类别名 * 如果是application中的 $this->instance('app', $this) 时候instances数组中不存在 app * app container 并且不需要build 则返回容器 */ if (isset($this->instances[$abstract]) && ! $needsContextualBuild) { return $this->instances[$abstract]; } /** * 保存参数到with数组中 */ $this->with[] = $parameters; /** * 如果contextual 中存在别名信息 返回对于信息的值 * 如果bindings 中存在别名信息 返回对于信息中的concrete键的值 * 如果上述都不成立 返回别名 */ $concrete = $this->getConcrete($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. /** * 如果$concrete 和$abstract相同 或者$concrete是一个匿名函数 条件成立 */ if ($this->isBuildable($concrete, $abstract)) { /** * 实例化$concrete 代码的类 */ $object = $this->build($concrete); } else { /** * 重新执行make函数 */ $object = $this->make($concrete); } // If we defined any extenders for this type, we'll need to spin through them // and apply them to the object being built. This allows for the extension // of services, such as changing configuration or decorating the object. /** * 获取extenders 中注册该别名对于的方法数组 逐个执行 */ foreach ($this->getExtenders($abstract) as $extender) { $object = $extender($object, $this); } // If the requested type is registered as a singleton we'll want to cache off // the instances in "memory" so we can return it later without creating an // entirely new instance of an object on each subsequent request for it. /** * 判断bindings或者instances中是否已经存在该别名信息 判断$needsContextualBuild值 */ if ($this->isShared($abstract) && ! $needsContextualBuild) { $this->instances[$abstract] = $object; } /** * 执行全局注册的函数事件globalResolvingCallbacks 该函数注册的事件 resolvingCallbacks * 完成实例化调用的全局事件globalAfterResolvingCallbacks 已经改函数实例化完成后调用的事件afterResolvingCallbacks */ $this->fireResolvingCallbacks($abstract, $object); // Before returning, we will also set the resolved flag to "true" and pop off // the parameter overrides for this build. After those two things are done // we will be ready to return back the fully constructed class instance. $this->resolved[$abstract] = true; array_pop($this->with); return $object; }
其中关键的实例化返回build函数说明
/** * 实例化一个对象 * @param unknown $concrete * @return unknown|void|object */ 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()); } /** * @link http://php.net/manual/zh/reflectionclass.construct.php * @return ReflectionClass $reflector */ $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. /** * @link http://php.net/manual/zh/reflectionclass.isinstantiable.php * 检查这个类是否可实例化 如果不能实例化 报错 */ if (! $reflector->isInstantiable()) { return $this->notInstantiable($concrete); } /** * 添加记录 */ $this->buildStack[] = $concrete; /** * 获取已反射的类的构造函数 * @link http://php.net/manual/zh/reflectionclass.getconstructor.php * @return ReflectionMethod $constructor */ $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. /** * 获取失败 弹出buildStack数据 返回一个实力 */ if (is_null($constructor)) { array_pop($this->buildStack); return new $concrete; } /** * 通过 ReflectionParameter 数组返回参数列表 * @link http://php.net/manual/zh/reflectionfunctionabstract.getparameters.php * @var ReflectionParameter $dependencies */ $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. /** * 返回类中的属性和对应的值 * @var array $instances */ $instances = $this->resolveDependencies( $dependencies ); /** * 弹出buildStack数据 */ array_pop($this->buildStack); /** * @link http://php.net/manual/zh/reflectionclass.newinstanceargs.php * 创建一个类的新实例,给出的参数将传递到类的构造函数 * * 给类中的属性赋值 */ return $reflector->newInstanceArgs($instances); }
通过resolveDependencies 获取类中属性的默认值 通过如果属性是一个匿名函数 则执行匿名函数 如果是一个类 值实例化类
/** * 返回对于属性的值 * @param array $dependencies * @return mixed[]|\Closure[]|unknown[] */ protected function resolveDependencies(array $dependencies) { $results = []; /** * @var ReflectionParameter $dependency */ foreach ($dependencies as $dependency) { // If this dependency has a override for this particular build we will use // that instead as the value. Otherwise, we will continue with this run // of resolutions and let reflection attempt to determine the result. if ($this->hasParameterOverride($dependency)) { $results[] = $this->getParameterOverride($dependency); continue; } // If the class is null, it means the dependency is a string or some other // primitive type which we can not resolve since it is not a class and // we will just bomb out with an error since we have no-where to go. /** * @link http://php.net/manual/zh/reflectionparameter.getclass.php * @var ReflectionClass $class * * 若该参数为对象,返回该对象的类名 * 如果不是一点对象 使用 resolvePrimitive方法 * 如果是一个对象对象信息 创建一个该对象 解决依赖问题 */ $results[] = is_null($class = $dependency->getClass()) ? $this->resolvePrimitive($dependency) : $this->resolveClass($dependency); } return $results; }
如果是一个配置的匿名函数 则通过resolvePrimitive返回执行该匿名函数 返回
/** * 如果是一个匿名对象 执行匿名对象 返回执行结果 * 如果是一个默认值 则返回默认值 * 如果不存在默认值 则报错 */ protected function resolvePrimitive(ReflectionParameter $parameter) { /**查询给定的别名 查询contextual 中是否存在信息 如果存在返回 如果是抽象类别名 游离抽象类数组 查询对于的别名是否存在contextual 中 存在返回 * 如果是一个匿名函数 值执行匿名函数 返回结果 如果不是你们函数 返回contextual中对于的值 */ if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) { return $concrete instanceof Closure ? $concrete($this) : $concrete; } /** * @link http://php.net/manual/zh/reflectionparameter.isdefaultvalueavailable.php * 查看是否存在默认值 */ if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } /** * 报错 */ $this->unresolvablePrimitive($parameter); }
如果该属性是一个类 则执行resolveClass 实例化该类
/** * 实例化对于的类 * @param ReflectionParameter $parameter * @throws BindingResolutionException * @return mixed|unknown|mixed */ protected function resolveClass(ReflectionParameter $parameter) { try { /** * 实例化类 */ return $this->make($parameter->getClass()->name); } // If we can not resolve the class instance, we will check to see if the value // is optional, and if it is we will return the optional parameter value as // the value of the dependency, similarly to how we do this with scalars. catch (BindingResolutionException $e) { if ($parameter->isOptional()) { return $parameter->getDefaultValue(); } throw $e; } }
posted on 2018-02-20 17:01 Sunlight1992 阅读(199) 评论(0) 编辑 收藏 举报