上一篇分析了应用的初始化,也就是对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;
添加到一个队列。最终的解析结果大概是这样的:
至此,全局中间件就加载完毕。
Bug天天改,头发日日疏,码字不易,如果有帮助到你,就点击"下方感谢"支持一下把.