laravel kernel解析过程
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解析过程的更多相关文章
- laravel的启动过程解析
laravel的启动过程,也是laravel的核心,对这个过程有一个了解,有助于得心应手的使用框架,希望能对大家有点帮助. 统一入口 laravel框架使用了统一入口,入口文件:/public/ind ...
- laravel的启动过程---摘自网络博客个人学习之用
如果没有使用过类似Yii之类的框架,直接去看laravel,会有点一脸迷糊的感觉,起码我是这样的.laravel的启动过程,也是laravel的核心,对这个过程有一个了解,有助于得心应手的使用框架,希 ...
- DNS原理及其解析过程 精彩剖析
本文章转自下面:http://369369.blog.51cto.com/319630/812889 DNS原理及其解析过程 精彩剖析 网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址 ...
- DNS解析过程详解
先说一下DNS的几个基本概念: 一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点 ...
- DNS解析过程
参考: http://www.maixj.net/ict/dns-chaxun-9208 http://blog.it985.com/8389.html DNS(Domain Name System) ...
- 解读JSP的解析过程
解读JSP的解析过程 互联网上,这方面的资料实在太少了,故把自己研究的一些结果公布出来. 首先,问大家几个问题,看大家能不能回答出来,或者在网上能不能找到答案: 1.page.include.tagl ...
- DNS原理及其解析过程【精彩剖析】(转)
2012-03-21 17:23:10 标签:dig wireshark bind nslookup dns 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否 ...
- dig理解DNS的解析过程 - 阿权的书房
关于DNS的常识,可以阅读附录的一些参考资料.本文旨在尝试举例用dig命令理解这个过程,并非权威知识,仅供参考.测试域名为阿权的书房的域名 www.aslibra.com 和 www.163.com. ...
- HiveSQL解析过程详解 | 学步园
HiveSQL解析过程详解 | 学步园 http://www.xuebuyuan.com/2210261.html
随机推荐
- JS时间和时间戳的转换
时间转为时间戳 timeToTimestamp(time){ let timestamp = Date.parse(time) return timestamp; } 时间戳转为本地时间 timest ...
- 如何让img自动适应div容器大小
IMG样式 (横向拉伸,纵向自动匹配大小) width:100%; height:auto; (纵向拉伸,横向自动匹配大小) width:auto; height:100%; DIV样式(元素居中显示 ...
- JS——变量提升和函数提升
一.引入 在了解这个知识点之前,我们先来看看下面的代码,控制台都会输出什么 var foo = 1; function bar() { if (!foo) { var foo = 10; } aler ...
- SparkBench安装使用入门
SparkBench安装以及快速开始 欢迎关注我的GitHub~ 本指南假定已经可以正常使用Spark 2.x,并且可以访问安装它的系统. 系统环境 CentOS 7.7.1908 Ambari-Sp ...
- 还分不清 Cookie、Session、Token、JWT?一篇文章讲清楚
还分不清 Cookie.Session.Token.JWT?一篇文章讲清楚 转载来源 公众号:前端加加 作者:秋天不落叶 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证 ...
- 【BZOJ4631】踩气球 题解(线段树)
题目链接 ---------------------- 题目大意:给定一个长度为$n$的序列${a_i}$.现在有$m$个区间$[l_i,r_i]$和$q$个操作,每次选取一个$x$使得$a_x--$ ...
- Kaggle-pandas(6)
Renaming-and-combining 教程 通常,数据会以列名,索引名或我们不满意的其他命名约定提供给我们. 在这种情况下,您将学习如何使用pandas函数将有问题的条目的名称更改为更好的名称 ...
- ECS7天实践进阶训练营Day2:基于阿里云ECS部署MediaWiki
一.概述 MediaWiki是全球最著名的开源Wiki程序,运行于PHP+MySQL环境,MediaWiki从2002年被作为维基百科的系统软件,并由大量其他应用实例(例如萌娘百科),因此MediaW ...
- Visual Studio安装
2017 安装的时候,一直显示,安装成功但是有告警. 解决方法: 将visual studio 2017 installer进行卸载,然后安装hw的ios 不能确保下次也可以成功
- 【计算机算法设计与分析】——SVM
一.简介 支持向量机(support vector machines)是一种二分类模型,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化,最终转化为一个凸二次规划问题来求解.由简至繁的 ...