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. Linux下利用docker搭建elasticsearch(单节点)

    1. 拉取镜像 #elasticsearch 6.x和7.x版本有很多不一样需要确认 docker pull docker.elastic.co/elasticsearch/elasticsearch ...

  3. day1. python注释及变量

    一.注释 1.单行注释 # # python 2.x print "你好" # python 3.x print("你好") 2.多行注释 ''' '''  或 ...

  4. JS pc端网页特效

    offset     offset翻译就是偏移量,可以使用他相关的属性可以动态的得到该元素的位置.大小等等     获得元素距离带有定位父元素的位置     获得元素自己的大小(宽度高度)     注 ...

  5. 关于手机数码圈KOL的一两点感想

    复工以来,高峰时段9号线地铁上的人依旧不少,安全距离啥的肯定是不用想了,只是从原来的4G手机换成5G手机以后在某些站能接收到5G信号,我终于能在一些原来根本没信号的站里愉快的刷一刷微博和酷安了. 但是 ...

  6. tableau用户留存分析

    1.数据源 这是个母婴产品的购买流水数据 2.数据处理 字段拆分.创建购买点会员生命周期 3.分析不同省份的留存率情况 根据第12个月的留存率对省市进行分组 实际业务中也可以通过类似的方法对用户年龄组 ...

  7. C++中inet_pton、inet_ntop函数

    - 头文件windows下:#include <WS2tcpip.h>linux下:#include <sys/socket.h>#include <netinet/in ...

  8. C#开发笔记之01-为什么开源框架会大量的使用protected virtual?

    C#开发笔记概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/957 访问. 我们在很多开源框架中会经常看到prote ...

  9. JavaFX桌面应用-视频转码工具(支持爱奇艺qsv转mp4)

    最近由于需要将在爱奇艺下载的视频(qsv)转化了mp4,用JavaFX开发一个视频转码工具,算是JavaFX开发的第一个应用吧. 支持qsv转码mp4,理论上支持各种格式,仅测试了flv,qsv格式. ...

  10. C++开发时字符编码的选择

    最近看了很多有关字符编码的讨论帖子, 自己也做了很多尝试, 针对linux和windows上字符编码的选择做了个简单整理, 在此做个记录 首先是基础编码知识, 下面我列出的4个编码方式或字符集是我们应 ...