ThinkPHP6 核心分析(四):加载中间件

说明

修改日志:2019-10-28 更新到6.0正式版

上一篇分析了应用的初始化,也就是对Http类的run()方法里面调用的runWithRequest ()方法的第一行代码$this->initialize()的展开分析。让我们再看一眼runWithRequest ()方法的前几行:

protected function runWithRequest(Request $request)
{
    $this->initialize();

    // 加载全局中间件
    $this->loadMiddleware();
    .
    .
    .

应用初始化后,接下来开始处理中间件。

中间件类的初始化

loadMiddleware方法:

protected function loadMiddleware(): void
{
    if (is_file($this->app->getBasePath() . 'middleware.php')) {
        $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
    }
}

依然是百用不厌的套路,通过$this->app->middleware来实例化中间件并获取其实例。

导入中间件

通过$this->app->middleware得到Middleware类的实例后,接着程序调用import方法,传入从「app」目录下的「middleware.php」文件中读取的数据。该文件的原始内容如下(原来全部注释掉的):

return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
     \think\middleware\LoadLangPack::class,
    // Session初始化
    // \think\middleware\SessionInit::class,
    // 页面Trace调试
     \think\middleware\TraceDebug::class,
];

这里为了研究中间件是如何加载的,先去掉两个注释,也就是添加两个中间件。接下来看import方法:

public function import(array $middlewares = [], string $type = 'global'): void
{
    foreach ($middlewares as $middleware) {
        $this->add($middleware, $type);
    }
}

该方法传入一个中间件的数组和一个中间件类型,默认为global,关键是里面的add方法。跳到add方法:

public function add($middleware, string $type = 'route'): void
{
    if (is_null($middleware)) {
        return;
    }

    $middleware = $this->buildMiddleware($middleware, $type);

    if ($middleware) {
        $this->queue[$type][] = $middleware;
        // 去除重复
        $this->queue[$type]   = array_unique($this->queue[$type], SORT_REGULAR);
    }
}

实际上真正干活的是buildMiddleware方法,直接前往:

protected function buildMiddleware($middleware, string $type): array
{
    // 是否是数组
    if (is_array($middleware)) {
        // 列出中间件及其参数
        // 这里说明我们可以给中间件传入参数,且形式为 [中间件, 参数]
        list($middleware, $param) = $middleware;
    }
    // 是否是一个闭包
    // 说明中间件可以是一个闭包
    if ($middleware instanceof \Closure) {
        //返回闭包和参数
        return [$middleware, $param ?? null];
    }
    // 排除了上面几种类型,且不是字符串,抛出错误
    if (!is_string($middleware)) {
        throw new InvalidArgumentException('The middleware is invalid');
    }

    //中间件别名检查
     $alias = $this->app->config->get('middleware.alias', []);

     if (isset($alias[$middleware])) {
        $middleware = $alias[$middleware];
    }

    //如果中间件有包含中间件(说明中间件可以嵌套)
    //再走一遍「import」递归解析
    if (is_array($middleware)) {
        $this->import($middleware, $type);
        return [];
    }
    //返回解析结果
    return [[$middleware, 'handle'], $param ?? null];
}

详细分析见以上代码注释。最后返回的结果,在add方法中,执行$this->queue[$type][] = $middleware;添加到一个队列。最终的解析结果大概是这样的(app/middleware.php去掉部分中间件的注释):

ThinkPHP6 源码阅读(四):加载中间件

至此,全局中间件就加载完毕。

本作品采用《CC 协议》,转载必须注明作者和本文链接
Was mich nicht umbringt, macht mich stärker
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!