Thinkphpv5.1 启动流程分析
本文最后更新于 10 天前,其中的信息可能已经有所发展或是发生改变。

继续学习TP5框架的启动流程,也就是在request请求后是如何response的。

Thinkphp5.1对底层架构做了进一步的改进,减少依赖,主要就是新增了容器(Container)、门面(Facade)、中间件(Middleware)三大块功能。

容器(Container)的功能,一句话概括就是管理对象实例,缓存已创建的实例。

加载基础文件

index.php分为两部分,一部分是加载基础文件,一部分是执行应用并响应。

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

// [ 应用入口文件 ]
namespace think;

// 加载基础文件
require __DIR__ . '/../thinkphp/base.php';

// 支持事先使用静态方法设置Request对象和Config对象

// 执行应用并响应
Container::get('app')->run()->send();

跟进加载基础文件,接着加载/library/think/Loader.php,最后调用_require_file包含文件并return。

接着跟进,分别调用了Loader类和Error类下的register()注册函数。

// 注册自动加载
Loader::register();

// 注册错误和异常处理机制
Error::register();

首先跟进Loader::register,先获得了网站目录和composer目录

判断在composerPath目录下是否存在autoload_static.php文件,如果存在则进行包含操作。

接着进行了命名空间的定义,简化了命名空间引用的繁杂度。

        self::addNamespace([
            'think'  => __DIR__,
            'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',
        ]);

最后加载插件目录

        self::addAutoLoadDir($rootPath . 'extend');

接着注册错误和异常处理机制,先是进行了一个文件包含的操作。

调用该类下的register()函数

最后实现日志接口,先判断是否存在 Psr\Log\LoggerInterface的extends,如果没有添加过该插件会注册一个孔的日志接口。

// 实现日志接口
if (interface_exists('Psr\Log\LoggerInterface')) {
    interface LoggerInterface extends \Psr\Log\LoggerInterface
    {}
} else {
    interface LoggerInterface
    {}
}

最后注册了类的别名,最后进入了Container的调用流程。

Container调用过程

这里先包含了Container.php文件,然后进入Container.php的get()函数

这里调用了Container获取实例的的函数,并且返回实例。这里的is_null返回true,内存中只有一个$instance存在。

    public static function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static;
        }

        return static::$instance;
    }

可以查看该$instance,绑定了之前注册的别名。

然后调用make方法,这里的$abstract赋值为app,concrete为think\App,也就是app类的命名空间。由于这里进入了else空间,所以return了调用的make,接着跟进make。

第二次进入make,$abstract值为think/App,由于bind数组没有存在该键名,所以进入了$this->invokeClass()。

这里比较关键的是调用反射实例化了App类,并且调用了App的构造,最后返回App。

回到原来的调用

Container::get('app')->run()->send();

通过上面的分析可知,Container::get('app')这里返回了App类,所以这里调用的run是App类中的run,接着跟进run函数。

路由分发

开始调用了初始化函数,跟进可知该函数对$app中的部分属性进行了赋值处理,并进行了一些初始化操作,例如设置环境变量、加载配置文件、注册命名空间、初始化应用、开启类名后缀、是否要开启debug模式判断、注册异常处理、注册根命名空间、数据库初始化、系统时区设置、路由初始化等等。而路由初始化进行了一个目录扫描并包含文件的操作。

            $this->initialize();

这里的$dispatch为空,所以进入了路由检测。

routeCheck()分别进行检测路由缓存、获取应用调度信息、判断是否开启强制路由模式,最后返回一个Dispath对象,调用该对象下的init,之后调用parseUrl,通过TP的方式解析路由并分装参数。

实例化Module,调用Init进行初始化,通过tp解析控制器和获取操作名的方法获得需要获得的变量,设置需要调用的控制器名和操作名,最后返回$this。

到这里的初始化就完成了,这里已经实现了路由分发、控制器和操作名设置等等,剩下的就是将需要将调度信息发送到应有的控制器进行执行,也就是调用send()方法。

执行调度

Thinkphp将对路由的处理放在了中间件中,这部分我也不是很熟悉,只能跟着其他人的分析流程走。

这部分传入我们包装好的路由信息,跟进到中间件的add函数

这里将传入的闭包添加到队列中

关注这里的函数,进入buildMiddleware

跟进后进入第二个return语句,如果为闭包的话就返回一个数组,数组中的值为$middleware$param。返回think\App跟进$this->mdiddleware->dispatch()

跟进$this->resolve,这里传入的值是’route’,在这里返回闭包。

跟进,上面分析了,$dispatch为UrlDispatch实例,这个实例中存储的dispatch属性是一个Moudle对象。进入Module,也就是MVC中的M,调用需要的控制器和方法。

跟进exec,跟初始化过程类似,实例化需要的控制器,如果不存在则返回报错信息

跟踪,会获取操作名和方法还有传入参数,最后进入invokeReflectMethod

这里绑定了参数,通过反射调用响应的类的方法。

兜兜转转进入控制器

将html源码作为返回值进行返回,最后进入日志。

到这里调用流程就结束了!

总结

启动流程分析起来总还是很复杂的,其实无非也是文件包含、环境变量配置、变量创建、分发路由和访问控制器,总体还是从request到response的传递。

参考

Thinkphp 5.1 启动流程浅析/控制器未过滤RCE[详细长文]

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇