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. Hadoop学习问题记录之基础篇

    目的 记录学习hadoop过程中遇到的基础问题,无关大小.无关困扰时间长短. 问题一 全分布式环境中运行mapred程序,报异常:java.net.NoRouteToHostException: 没有 ...

  2. day2. 六大基本数据类型简介

    一.基本数据类型 Number 数字类型 (int float bool complex) str 字符串类型 list 列表类型 tuple 元组类型 set 集合类型 dict 字典类型 二.Nu ...

  3. NCoreCoder.Aop详解

    于今天,功能终于完善度到比较满意的程度了 准备好好写一篇文章,而不是之前的流水账,分享一下最近这些天的踩坑 一开始AOP选的微软提供的DispatchProxy 关于这个,有大佬的文章,可以看看,了解 ...

  4. ios企业签名为什么会掉签?

      我们都知道ios用户无法直接安装App Store之外的应用,对于那些无法上架苹果应用商店的APP,开发者们一般会选择苹果签名的形式.   目前的苹果签名有ios企业签名.超级签名和TF上架这三种 ...

  5. Pytest单元测试框架-allure测试报告

    Allure Test Report 对于不同的编程语言,有很多很酷的测试框架.不幸的是,它们中只有少数能够提供测试执行输出的良好表示.Qameta软件测试团队正在致力于Allure--一个开源框架, ...

  6. mysql主主半同步

    1.半同步概述 先了解下mysql的几种复制 异步复制MySQL复制默认是异步复制,Master将事件写入binlog,提交事务,自身并不知道slave是否接收是否处理:缺点:不能保证所有事务都被所有 ...

  7. CRF

  8. 基于Asp.net Core 3.1实现的Redis及MemoryCache缓存助手CacheHelper

    这几天在面试,这个关于Redis缓存的博客一直没空写,今天总算有点时间了. 从很久很久之前,我就一直想学Redis了,反正看到各大招聘网上都要求Redis,不学就太落后了. 一开始我是按微软官网文档那 ...

  9. 前端自适应样式(reset.css)

    @charset "utf-8"; /* CSS Document */ html, body, ul, li, ol, dl, dd, dt, p, h1, h2, h3, h4 ...

  10. ASP.NET Core - 实现Http自定义请求头策略

    前言 在正常的情况下,当我们系统用到JWT认证方式时,需要在Http请求头添加Authorization: XXX,这样在后台服务的控制器中打上[Authorize]授权标签,就限定所有的请求必须通过 ...