最近一直在看tp6的源码,运行逻辑,然后一直卡到了中间件运行的部分。
$pipeline = array_reduce( array_reverse($this->pipes), $this->carry(), function ($passable) use ($destination) { try { return $destination($passable); } catch (Throwable | Exception $e) { return $this->handleException($passable, $e); } } );
array_reverse里面装的全是闭包然后传入了定义时的中间件名称,然后把闭包参数传给 $this->carry()方法
protected function carry() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { try { return $pipe($passable, $stack); } catch (Throwable | Exception $e) { return $this->handleException($passable, $e); } }; }; }
array_reduce 第一个参数是一个数组,第二个参数是一个方法,第三个参数是一个默认值
因为第二个参数每次会调用2个参数 第一个参数为上一次调用的结果,第二个参数为当前数组值
$testArr=[1,2,3]; function test($first , $two){ return $first+$two; } //array_reduce的每次调用就是 test(null,1); test(null+1,2); test(null+1+2,3); //如果有第三个参数假设为 5 test(5,1); test(5+1,2); test(5+1+2,3);
也就是将上一次的结果继续做下次运算。
而tp6里的第一个参数装载的都是闭包(Closure)
return function ($request, $next) use ($middleware) { [$call, $params] = $middleware; if (is_array($call) && is_string($call[0])) { $call = [$this->app->make($call[0]), $call[1]]; } $response = call_user_func($call, $request, $next, ...$params); if (!$response instanceof Response) { throw new LogicException('The middleware must return Response instance'); } return $response; };
$middleware 指向的就是用户定义和tp6自定义的中间件地址
这个闭关会去调用中间件地址的handle方法(解析中间件的时候默认指定的handle方法)
protected function carry() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { try { return $pipe($passable, $stack); } catch (Throwable | Exception $e) { return $this->handleException($passable, $e); } }; }; }
这就对所有闭关进行了一个嵌套,每当你运行当前函数时候都会把上一个闭包当参数传递进来。运行的时候感觉就是这样的不知道对不对。
$default=function(){ echo 'default<br>'; }; $a=function($next){ return function()use($next){ echo 'a<br>'; $next(); }; }; $b=function($next){ return function()use($next){ echo 'b<br>'; $next(); }; }; $c=function($next){ return function()use($next){ echo 'c<br>'; $next(); }; }; $p = $c($b($a($default))); $p(); /* 结果: c b a default */
具体在default前面还是后面 就看你调用next()的是在你输出前还是后面。
由于array_reduce运行数组是从左到右,但是暴露出来的结果一定是最上层的(最右边)所以对数组进行反转(array_reverse) ,那么运行的结果就是先执行Test中的handel方法然后执行TestTwo中的handle。
//middleware配置文件
app\middleware\Test::class,
app\middleware\TestTwo::class,
//Test Class
namespace app\middleware;
class Test{
public function handle($request,$next){
echo 1;
return $next($request);
}
}
//TestTwo Class
namespace app\middleware;
class TestTwo{
public function handle($request,$next){
echo 2;
return $next($request);
}
}
//对于之前已经装载好的闭包其实就是
/*
//$request是之前示例好的对象
//闭包最里层装载的tp的初始化的东西返回是response对象
$one = function ($request) {
return $this->dispatchToRoute($request);
}
//这里就相当于自己运行的方法了
$testTwoHandle = function($request,$next){
echo 2;
return $next($request);
}
testHandle($request,$next){
echo 1;
return $next($request);
}
testHandle($request,$testTwoHandle );
*/