pipeline执行后返回值为null,是因为每个中间件函数必须显式return $passable(或新值),否则默认返回null导致后续环节接收null。

为什么 Pipeline 执行后返回值总是 null?
常见现象:链式调用 pipe() 后,then() 回调里拿到的参数是 null 或原始输入没被修改。根本原因是中间件函数没显式 return 下一个值——Laravel 的 Pipeline 不自动透传,每个 pipe 必须手动返回传递给下一个环节的数据。
- 错误写法:
function ($passable) { session()->flash('msg', 'done'); }(无返回)→ 下一环节收到null - 正确写法:
function ($passable) { session()->flash('msg', 'done'); return $passable; } - 如果中间件要“终止流程”,可返回非
$passable类型(比如redirect()响应),但需确保后续逻辑能处理该类型
then() 的回调参数到底是啥?
then() 接收的回调函数,其第一个参数是整个 pipeline 最终的返回值,也就是最后一个 pipe 函数的 return 值。它不是原始输入的引用,也不自动包含上下文对象——除非你主动把它们打包进去。
- 原始输入通过
send($value)传入,之后全程作为$passable流转 - 若某个
pipe返回了新对象(如new Response(...)),后续pipe就会收到这个新对象,then()也拿到它 - 别依赖“隐式状态”,比如在中间件里改全局变量再指望
then()读取——不可靠且难测试
如何让中间件接收额外参数(比如配置或服务)?
Laravel Pipeline 默认只把 $passable 作为唯一参数传给每个闭包。要注入其他依赖,得靠 Laravel 容器绑定 + 匿名函数 use 或提前解析。
- 推荐方式:用
via()指定调用方法,并将中间件定义为类,由容器自动注入依赖:->pipe(PermissionCheck::class)->via('handle') - 闭包场景下,可用
use ($service, $config)捕获外部变量,但注意生命周期——这些变量在 pipeline 构建时就已确定,无法动态切换 - 避免在闭包里直接 new 实例,会导致无法 mock、难以复用;优先走容器解析
自定义 Pipeline 类时,through() 数组顺序会影响什么?
顺序决定执行流,但更关键的是:中间件之间是否相互依赖返回值类型。比如 A 返回 Collection,B 期望接收 Collection 并调用 map(),那 B 就必须放在 A 后面。
- 顺序错乱最典型的表现是 “Call to a member function xxx on null” 或 “xxx method does not exist”
- 调试技巧:在每个
pipe开头加throw new Exception(gettype($passable).': '.print_r($passable, true));快速定位类型断裂点 - 不要为了“统一入口”强行把所有逻辑塞进 pipeline——比如数据库事务、日志记录这类副作用操作,更适合放在
then()外围处理
return,整条链就静默断掉,debug 成本远高于写的时候多敲两个字符。










