管道核心就一行逻辑:array_reduce 配 array_reverse,帖子卡在 through() 这里,真正的主角其实是紧接着的 then()。
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes),
function ($next, $pipe) {
return function ($passable) use ($next, $pipe) {
return $pipe->handle($passable, $next);
};
},
$destination
);
return $pipeline($this->passable);
}
为什么必须 array_reverse:array_reduce 是从数组头部往尾部"套娃"的,第一轮包出来的是最内层。你要的效果是「限流最外层、控制器最内层」,那就得先把数组倒过来,让最后注册的先被包进去。忘了 reverse 的表现是中间件执行顺序整个反了,而且往往不报错,特别隐蔽。
返回类型要统一:所有中间件和终点回调都必须返回同一个响应对象。一旦某个中间件短路时 return redirect() 返回了别的类型,外层那些 $response->headers->set(...) 就会炸在 null 或字符串上。建议在框架里给响应定个接口约束。
带参数怎么拆:注册时写成 role:editor,then() 里 explode(':', $pipe, 2),把 [0] 交给容器 new 出来、[1] 作为第三个参数塞进 handle。别用 new $pipe,带构造依赖的中间件会直接崩。
最后提醒一个最容易踩的坑:中间件里忘了写 return $next($request)。PHP 不会报错,管道静默返回 null,后置逻辑全部失效,排查起来能磨一下午。调试期可以在 then() 里加个断言,非对象返回值直接抛异常。
如果想把这类横切逻辑接进自研框架,建议按「全局 → 分组 → 路由」三段注册、依次合并成一个数组再进管道,跟 Laravel 的心智模型一致;像 Clara 那种插件钩子体系本质上也是同一套思路,只是把管道换成了事件点而已。
见习用户






