Pipeline 是 Laravel 中同步、线性、可中断的中间件式调用链,适用于需按序校验或加工输入的场景(如订单风控、API 参数标准化),不适用于异步或并行任务。

Pipeline 是什么,什么时候该用它
Laravel 的 Pipeline 不是“流式处理”的语法糖,也不是替代队列或事件的方案。它本质是一个**同步、线性、可中断的中间件式调用链**,适合把一个输入(比如请求数据、订单对象)按固定顺序交由多个职责单一的处理器(callable 或类)逐层加工或校验。
典型适用场景:创建订单前的风控检查(验证库存 → 检查用户额度 → 校验地址有效性)、API 请求参数标准化(trim → filter → cast → validate)、导出数据前的字段映射与脱敏。
不适合的场景:异步任务、需要并行执行的步骤、步骤间无明确输入输出依赖关系的逻辑。
如何正确实例化并运行 Pipeline
别直接 new Pipeline —— Laravel 已在容器中绑定了 \Illuminate\Pipeline\Pipeline,应通过容器解析或 Facade 使用:
- 推荐方式:
app(\Illuminate\Pipeline\Pipeline::class)或use Illuminate\Pipeline\Pipeline;+ 依赖注入 - 不要手动传入
$container参数后调用send()和through()再then()—— 容器未正确绑定时会丢失服务解析能力(比如你在处理器里app(MyService::class)失败) -
then()接收的是一个闭包,不是最终处理器;这个闭包会在所有中间件执行完毕后被调用,接收最终的返回值
use Illuminate\Pipeline\Pipeline;
$result = app(Pipeline::class)
->send($order)
->through([
CheckInventory::class,
CheckCreditLimit::class,
ValidateShippingAddress::class,
])
->then(function ($order) {
return $order->save();
});
自定义处理器类必须满足的结构
Laravel 对处理器类没有强制接口约束,但约定必须提供 handle() 方法,且签名必须为 handle($passable, Closure $next)。漏掉 $next 或参数顺序错误会导致管道中断或报错 Too few arguments to function。
关键细节:
-
$passable是上一步返回的值(默认是初始send()的值),不是原始输入副本 - 必须显式调用
$next($passable)才能进入下一步;不调用就终止,后续处理器完全不执行 - 可以在任意步骤抛出异常中断流程(如库存不足直接 throw new \Exception('Out of stock')),无需返回 false
- 类中可以使用构造函数注入依赖,Laravel 容器会自动解析(前提是类已注册或符合自动解析规则)
class CheckInventory
{
public function __construct(private InventoryService $inventory)
{
}
public function handle($order, Closure $next)
{
if (! $this->inventory->hasEnough($order->product_id, $order->quantity)) {
throw new \DomainException('Insufficient inventory');
}
return $next($order); // 继续往下传
}
}
常见陷阱:变量引用、返回值覆盖与调试困难
Pipeline 默认是「值传递」语义,但如果你在某步中修改了对象属性(比如 $order->status = 'checking'),后续步骤看到的就是已被修改的对象 —— 这不是 bug,是 PHP 对象引用的自然行为。容易误以为“没传过去”,其实是传了,只是被改了。
调试时难定位问题?Pipeline 不会自动记录每步耗时或返回值。建议:
- 在每个
handle()开头加日志:Log::debug('CheckInventory started', ['order_id' => $order->id]); - 避免在
then()闭包里写复杂逻辑;它只该做“收尾动作”,比如保存、返回响应。复杂后续操作应拆成独立服务 - 不要在处理器里返回
null或false期望中断流程 —— 必须抛异常或不调用$next(),否则$next(null)会继续执行,可能引发后续步骤的类型错误
真正麻烦的点往往不在写法,而在于多人协作时对“谁负责重置状态”“是否允许中途修改原始对象”缺乏共识。Pipeline 看似简单,但它的隐式数据流会让边界变得模糊。










