Laravel 源码学习笔记 3:App 容器解析 kernel 实例
上篇文章,介绍了初始化app容器对象并注册了一些基础服务,这篇讲app容器解析http的kernel实例。
http请求的kernel核心类在app实例初始化后就进行了绑定
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
可以看到Illuminate\Contracts\Http\Kernel::class 的实现类是 App\Http\Kernel::class,而App\Http\Kernel::class又继承Illuminate\Foundation\Http\Kernel::class,所以当app容器要解析个kernel对象的时候,就会去根据已经绑定好的依赖找对应的实现类。
//解析kernel http 核心类
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
查看Application.php的make方法
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($abstract);
if ($abstract == 'Illuminate\Contracts\Http\Kernel'){
// dd($parameters);
}
//如果这个服务是延迟加载的,就去触发延迟加载服务提供者方法
if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
$this->loadDeferredProvider($abstract);
}
//返回接口解析的对象
return parent::make($abstract, $parameters);
}
查看父类container.php的make方法
public function make($abstract, array $parameters = [])
{
return $this->resolve($abstract, $parameters);
}
protected function resolve($abstract, $parameters = [])
{
$abstract = $this->getAlias($abstract);
$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.
// 如果已经存在该服务的实例就直接返回
if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
return $this->instances[$abstract];
}
$this->with[] = $parameters;
$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.
// 判断是否还存在依赖,如果还在,就去析嵌套的依赖,直到它们可以去构建
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete);
} else {
$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.
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.
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}
$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;
}
从返回的变量名称可以看出,返回的就是个对象实例,也就是说make方法返回该绑定的实例,里面有个$this->build方法,点进去发现
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)) {
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);
}
build 就是利用反射获取了类对象,就这样,kernel的实例,就从容器中解析出来了。
有什么不对或有疑问的地方请大佬们指正:)
本作品采用《CC 协议》,转载必须注明作者和本文链接