laravel kernel解析过程

前面的两篇laravel文章过后,可以在bootstrap/app.php中拿到$app这个实例,

app.php中 接下来通过singleton方法绑定了三个闭包(闭包代表未完成解析,需要在使用到的时候动态解析)到容器中。

然后将$app返回到index.php中

<?php

$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
); $app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
); $app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
); $app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
); return $app;
  • 在index.php中可以看到尝试解析了Illuminate\Contracts\Http\Kernel::class
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// 重走一遍解析时的路 之前介绍过 make方法调用的是resolve方法,最终通过build拿到闭包直接产生类或者通过php提供的反射api进行动态解析,最终返回需要的实例。

Container中的resolve方法
protected function resolve($abstract, $parameters = [], $raiseEvents = true)
{
1 // 联系前文getAlias返回的还是$abstract本身,也就是Illuminate\Contracts\Http\Kernel
$abstract = $this->getAlias($abstract); $needsContextualBuild = !empty($parameters) || !is_null(
$this->getContextualConcrete($abstract)
); if (isset($this->instances[$abstract]) && !$needsContextualBuild) {
return $this->instances[$abstract];
} $this->with[] = $parameters; // 获取concrete实例 发现得到一个闭包 该闭包是app.php中通过singleton绑定生成的 其中调用了resolve方法,具体可以查看前文的singleton->bind->getClosure方法
$concrete = $this->getConcrete($abstract); // isBuildable只要concrete是闭包 恒真
3 // 跳转回来isBuildable方法 此时$concrete == $abstract 同样调用build方法,再次跳转到build方法
if ($this->isBuildable($concrete, $abstract)) {
// 跳转到build方法
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
} foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
} 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)
{
2 // 此时传递进来的是 返回App\Http\Kernel的闭包
if ($concrete instanceof Closure) {
// 走进这个分支 如果是闭包直接调用 前面说过这个闭包保存的是resolve方法 其中的concrete是App\Http\Kernel类名,所以在此相当于调用$app->resolve(App\Http\Kernel),又回到了resolve方法
return $concrete($this, $this->getLastParameterOverride());
} 4 // 解析App\Http\Kernel 用到了大量的php反射api 请自行查阅手册
try {
$reflector = new ReflectionClass($concrete);
} catch (ReflectionException $e) {
throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
} if (!$reflector->isInstantiable()) {
return $this->notInstantiable($concrete);
} $this->buildStack[] = $concrete; $constructor = $reflector->getConstructor(); // 若没有构造函数,表示不需要继续解析依赖了,直接返回了实例
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
} // 获取依赖
$dependencies = $constructor->getParameters(); try {
// 解析依赖 跳转到resolveDependencies方法
$instances = $this->resolveDependencies($dependencies);
} catch (BindingResolutionException $e) {
array_pop($this->buildStack); throw $e;
} array_pop($this->buildStack); // 返回解析好依赖的实例
return $reflector->newInstanceArgs($instances);
} // 此方法循环解析要解析的依赖并返回,通过反射进行实例的返回,从而完成实例从容器中的解析
protected function resolveDependencies(array $dependencies)
{
$results = [];
// $dependencies通过php原生反射机制得到的对应类的构造方法中的依赖,针对此App\Http\Kernel得到应该如下
// array (size=2)
// 0 =>
// object(ReflectionParameter)[32]
// public 'name' => string 'app' (length=3)
// 1 =>
// object(ReflectionParameter)[33]
// public 'name' => string 'router' (length=6)
/**
* App\Http\Kernel的构造方法长这样
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Routing\Router $router
* @return void
*/
// public function __construct(Application $app, Router $router)
// {
// $this->app = $app;
// $this->router = $router;
// $this->syncMiddlewareToRouter();
// } foreach ($dependencies as $dependency) {
if ($this->hasParameterOverride($dependency)) {
$results[] = $this->getParameterOverride($dependency); continue;
} // 因为App\Http\Kernel的构造方法中存在类型提示,所以getClass返回的不是null
// 从而走到resolveClass方法中
$results[] = is_null($dependency->getClass())
? $this->resolvePrimitive($dependency)
// 跳转到resolveClass方法
: $this->resolveClass($dependency);
} return $results;
} protected function resolveClass(ReflectionParameter $parameter)
{
try {
// 通过getClass方法获取实例的类型约束。在此递归调用make方法,直到返回所有的依赖,从而通过newInstanceArgs(deps)获得从容器中解析的实例
5 // 再次跳到make->resolve方法 针对App\Http\Kernel 传递的两个依赖的type hint为
// Illuminate\Contracts\Foundation\Application
// Illuminate\Routing\Router
// Application解析返回的是 $app->instances['app'] 在registerBaseBindings绑定的
// Router解析返回的是$app->bindings['router']闭包 在registerBaseServiceProvider中注册的
// 前文都有提到
// 至此解析除了App\Http\Kernel类,得到了laravel传说中的‘黑盒子’
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;
}
}

本文和之前内容存在重复,通过laravel实际的解析例子再熟悉下解析流程,发现错误欢迎指点。

laravel kernel解析过程的更多相关文章

  1. laravel的启动过程解析

    laravel的启动过程,也是laravel的核心,对这个过程有一个了解,有助于得心应手的使用框架,希望能对大家有点帮助. 统一入口 laravel框架使用了统一入口,入口文件:/public/ind ...

  2. laravel的启动过程---摘自网络博客个人学习之用

    如果没有使用过类似Yii之类的框架,直接去看laravel,会有点一脸迷糊的感觉,起码我是这样的.laravel的启动过程,也是laravel的核心,对这个过程有一个了解,有助于得心应手的使用框架,希 ...

  3. DNS原理及其解析过程 精彩剖析

    本文章转自下面:http://369369.blog.51cto.com/319630/812889 DNS原理及其解析过程 精彩剖析 网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址 ...

  4. DNS解析过程详解

    先说一下DNS的几个基本概念: 一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点 ...

  5. DNS解析过程

    参考: http://www.maixj.net/ict/dns-chaxun-9208 http://blog.it985.com/8389.html DNS(Domain Name System) ...

  6. 解读JSP的解析过程

    解读JSP的解析过程 互联网上,这方面的资料实在太少了,故把自己研究的一些结果公布出来. 首先,问大家几个问题,看大家能不能回答出来,或者在网上能不能找到答案: 1.page.include.tagl ...

  7. DNS原理及其解析过程【精彩剖析】(转)

      2012-03-21 17:23:10 标签:dig wireshark bind nslookup dns 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否 ...

  8. dig理解DNS的解析过程 - 阿权的书房

    关于DNS的常识,可以阅读附录的一些参考资料.本文旨在尝试举例用dig命令理解这个过程,并非权威知识,仅供参考.测试域名为阿权的书房的域名 www.aslibra.com 和 www.163.com. ...

  9. HiveSQL解析过程详解 | 学步园

    HiveSQL解析过程详解 | 学步园   http://www.xuebuyuan.com/2210261.html

随机推荐

  1. luogu P2462 [SDOI2007]游戏

    LINK:SDOI2007游戏 题意:接龙前一个要比后面大1 且后一个单词出现的各自字母的次数>=前一个单词各自的字母的次数 考虑暴力dp sort之后dpY 显然会T. 考虑我们没必要枚举j ...

  2. 【原创】xenomai与VxWorks实时性对比(资源抢占上下文切换对比)

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有问题,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ (下面数据,仅供个人参考) 可能大部分人一直好奇Vx ...

  3. RabbitMQ学习总结(1)-基础概念

    1. 概念 1.1 AMQP协议 AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消 ...

  4. .NET三层架构各项目之间的引用关系及如何添加引用?

    1.1三层之间的引用 整个.NET框架的项目创建完成之后,在开发之前,还需要建立各个项目之间的引用关系,以便在编写C#业务逻辑代码时调用相关项目的类库. 1.1.1 引用关系规则 .NET三层架构中的 ...

  5. 分析"傍富婆发财"

    视频地址https://www.bilibili.com/video/BV1pZ4y1u7jf 半佛 被富婆阿姨毒打的原因: 1.地位不对等导致工具化 资源不对等的情况下,尤其是一方极度依赖另一方资源 ...

  6. Elasticsearch从入门到放弃:瞎说Mapping

    前面我们聊了 Elasticsearch 的索引.搜索和分词器,今天再来聊另一个基础内容-- Mapping. Mapping 在 Elasticsearch 中的地位相当于关系型数据库中的 sche ...

  7. SQL Server2017+SSIS+Python

    1.安装SQL Server2017 https://jingyan.baidu.com/article/76a7e409077997fc3a6e1559.html (1)JRE 7报错 只能安装JR ...

  8. C#设计模式之13-职责链模式

    职责链模式(Chain of Responsibility Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archive ...

  9. C#LeetCode刷题之#258-各位相加(Add Digits)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3860 访问. 给定一个非负整数 num,反复将各个位上的数字相加 ...

  10. 使用pytorchviz进行模型可视化出现 'NoneType' object has no attribute 'grad_fn'

    问题 最近学习pytorch, 原来用kreas重现的模型改为用pytorch实现训练,因为这样给模型的操作更加细致, 对模型的掌控更好. 当我写好一个模型 出现了这个问题 使用pytorchviz进 ...