内容简介:Laravel 之道第六章:服务容器之 make
先来段代码
下面是 public/index.php
入口文件的一段代码,相信大家都见过
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
它作用解析出在服务容器 bindings
属性中以 'Illuminate\Contracts\Http\Kernel'
为键,对应的服务对象。据上一章我们知道是 'App\Http\Kernel'
的类对象
注意:以
'Illuminate\Contracts\Http\Kernel'
为键,实际对应不是'App\Http\Kernel'
的类对象,而是对应能够生成'App\Http\Kernel'
类对象的闭包函数。
那么他是如何解析出的呢,我们看一下源码
public function make($abstract, array $parameters = [])
{
return $this->resolve($abstract, $parameters);
}
实际调用了 resolve 方法,我们看一下 resolve 方法。
看下面这方法,是不是头大,这么多,其实核心的就那么几个地方,我已标注
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;
// ★核心二★:通过 $abstract 到 bindings 属性中取得生成对象的闭包函数,没有则返回 $abstract 本身
$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.
// ★核心三★:判断是否可以创建对象,来确定调用 build 方法还是重新调用 make 方法
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;
}
由于第一次执行,核心一忽略。当以 'Illuminate\Contracts\Http\Kernel'
为 $abstract 时,获取的闭包函数定义的位置如下
protected function getClosure($abstract, $concrete)
{
return function ($container, $parameters = []) use ($abstract, $concrete) {
if ($abstract == $concrete) {
return $container->build($concrete);
}
return $container->make($concrete, $parameters);
};
}
会执行上面代码 function 里面的内容,因为 Illuminate\Contracts\Http\Kernel
不等于 App\Http\Kernel
,故以 App\Http\Kernel
为 $abstract 重新调用了 make 方法
此时的 make 方法可以执行到 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);
}
此时的 $concrete 等于 'App\Http\Kernel'
,会调用 PHP 内置的反射类,对 App\Http\Kernel
进行处理。
关于 ReflectionClass
ReflectionClass:我的理解是,这是一个对类进行处理的对象,它甚至能够获取类中的注释,执行类中的私有方法;getConstructor
返回一个 ReflectionMethod
对象,它可以对类中方法进行更进一步处理和控制,比如获取方法调用时的参数列表,包含参数的类型约束,这点很重要,因为它是 Laravel 实现依赖注入的手段;反射方法对象中的 getParameters
将返回一个 ReflectionParameter
对象,它里面就包含了类型约束和参数名称。
$instances = $this->resolveDependencies(
$dependencies
);
看到上面这段代码了吗,resolveDependencies
方法,就是解析出类构造方法中的约束类,通过多次 make 自动获取所依赖的对象,然后通过反射类的 newInstanceArgs
实例化
最终获取了 App\Http\Kernel
类的对象,并且仅仅通过一行字符串,其中构造函数所依赖的对象,全部由 make 自动处理,用户可以不再管理那个依赖这个依赖了,不仅变得方便、变得解耦,还变得功能健全
我们是一群被时空压迫的孩子。 ---- 爱因斯坦
以上所述就是小编给大家介绍的《Laravel 之道第六章:服务容器之 make》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 容器服务Windows Kubernetes使用阿里云日志服务来收集容器日志
- 容器、微服务和服务网格简史
- 阿里云容器服务:负载均衡与容器的关系
- 微服务实践(二):微服务与服务容器化
- 简单优化容器服务
- 一起学习微服务和容器2-微服务的框架
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Google 广告高阶优化(第3版)
【美】Brad Geddes(布兰德.盖兹) / 宫鑫、康宁、王娜 / 电子工业出版社 / 2015-9 / 99.00元
《Google 广告高阶优化(第3版)》可以说是Google AdWords的终极指南,内容非常丰富,第三版在内容上进行了全面更新。介绍了AdWords的最新最完整的功能,阐释其工作原理,也提供了相应的优化方法、策略和实践教程,读者可以随时在自己的PPC广告系列中进行实践。第三版增添了50多页新内容,涵盖Google系统最近的所有变动,包括广告系列结构的变化、出价调整器、重定向、视频广告功能、全新......一起来看看 《Google 广告高阶优化(第3版)》 这本书的介绍吧!