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. LVS-DR:搭建HTTP和HTTPS负载均衡集群

    目录 LVS-DR实战:搭建HTTP和HTTPS负载均衡集群 1. 搭建lvs-dr模式的http负载集群 1.1 LVS上配置IP 1.2 RS上配置arp内核参数 1.3 RS上配置VIP 1.4 ...

  2. Python爬取10000条“爆款剧”——《三十而已》热评,并做可视化

    前言 继<隐秘的角落>后,又一部“爆款剧”——<三十而已>获得了口碑收视双丰收,王漫妮.顾佳.钟晓芹三个女主角的故事线频频登上微博热搜.该剧于2020年7月17日在东方卫视首播 ...

  3. 【python接口自动化】- logging日志模块

    前言:我们之前运行代码时都是将日志直接输出到控制台,而实际项目中常常需要把日志存储到文件,便于查阅,如运行时间.描述信息以及错误或者异常发生时候的特定上下文信息. logging模块介绍 ​ Pyth ...

  4. 014_go语言中的变参函数

    代码演示 package main import "fmt" func sum(nums ...int) { fmt.Print(nums, " ") toto ...

  5. 002_go语言的值类型

    代码演示: package main import "fmt" func main() { fmt.Println("go"+"lang") ...

  6. JS 弹出框拖拽

    css代码 body { margin:; text-align: center; } .box { display: none; background-color: #fff !important; ...

  7. 2020-05-26:TCP四次挥手过程?

    福哥答案2020-05-26:

  8. JavaScript 数组中根据某个属性值的中文进行排序

    普通排序 const arr = [] arr.sort((x, y) => x.prop - y.prop) 中文属性值排序 const arr = [] arr.sort((x, y) =& ...

  9. Spring Boot整合ElasticSearch和Mysql 附案例源码

    导读 前二天,写了一篇ElasticSearch7.8.1从入门到精通的(点我直达),但是还没有整合到SpringBoot中,下面演示将ElasticSearch和mysql整合到Spring Boo ...

  10. JavaScript基础-01

    1. Javascript是一门动态的.弱类型的.解释型的脚本语言 动态:数据类型在运行时决定 弱类型:变量数据的类型不是确定的,可以随意的进行改变: 解释型:相对编译型来说,编译型计算机在执行之前需 ...