pipeline 不是链式调用语法糖,因其核心价值在于责任分离与运行时动态组装,每个处理器只专注单一职责(如校验、脱敏),且 then() 返回最后一步结果,支持中途终止、类型可变、需显式实现 __invoke($passable, $next)。

为什么 Pipeline 不是「链式调用」的语法糖?
因为它的核心价值不在写法简洁,而在责任分离和运行时动态组装。你传给 send() 的值会依次被每个闭包或类处理器处理,且每个处理器只关心自己那一步的逻辑——比如权限校验、参数标准化、数据脱敏。如果把它当 collect()->map()->filter() 那样用,就浪费了它的中间件式控制流能力。
常见错误现象:Class App\Pipes\ValidatePipe does not exist,本质是没注册自动加载,或用了匿名函数却忘了在 pipe() 里显式传入实例。
- 必须确保每个 pipe 是可调用的:类需实现
__invoke(),或直接传闭包 - 类 pipe 推荐用完整命名空间路径字符串(如
'App\Pipes\TrimPipe'),Laravel 会自动 resolve - 闭包 pipe 要注意变量作用域,
use ($request)很容易漏掉引用
then() 返回值怎么接?别默认它返回原始输入
很多人以为 Pipeline 只是“过一遍”,最后一定拿到最开始传进来的那个 $request 或 $data。其实每个 pipe 的返回值都会作为下一个 pipe 的输入,then() 的结果就是最后一个 pipe 的返回值——它可能是个布尔值、数组、模型实例,甚至 null。
使用场景:做 API 请求预处理时,你可能希望最终得到一个已验证并转换好的 OrderRequestDTO 对象,而不是原始 Request。
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
- 如果某个 pipe 返回
false或抛出异常,后续 pipe 不再执行(除非你手动 catch) - 想中途终止并返回特定结构,直接
return response()->json(...)即可,但要注意这会让类型变得不可预测 - 调试时加个日志 pipe:
function ($passable) { \Log::debug('pipeline input:', ['value' => $passable]); return $passable; }
Laravel 10+ 的 Illuminate\Pipeline\Pipeline 默认不支持数组参数
如果你习惯把多个参数塞进数组传给 send(),比如 send(['user' => $user, 'post' => $post]),然后在 pipe 里期望解构,会发现所有 pipe 收到的都是这个数组——但 Laravel 的 pipeline 没有内置解包逻辑,它只认单个“通行物”(passable)。
性能影响:强行在每个 pipe 里 extract($passable) 或 array_merge(...) 会增加开销,也破坏语义清晰性。
- 正确做法是封装成对象(如
class PostPublishContext),让类型和意图明确 - 如果坚持用数组,统一在第一个 pipe 里解构并返回新对象,后面 pipe 就不再面对数组
- 别在
then()后面链式调用->toArray()之类方法——它不是 Collection
自定义 pipe 类必须实现 __invoke(),且参数签名不能错
这是最容易卡住的地方:Laravel 在 resolve pipe 类后,会以 $pipe($passable, $next) 方式调用,所以 __invoke() 必须接收两个参数,且第二个必须是 Closure 类型的 $next。少一个参数、类型不对、或者写了 public function handle() 却没配 handles 属性,都会导致 Too few arguments 错误。
示例正确写法:
class AuthCheckPipe
{
public function __invoke($passable, Closure $next)
{
if (! $passable->user()->can('publish', $passable->post)) {
throw new AuthorizationException();
}
return $next($passable);
}
}
- 不要试图在
__invoke()里做耗时操作(如 DB 查询)却不加缓存,pipe 是同步阻塞执行的 - 如果需要依赖注入,Laravel 会自动注入,但仅限构造函数;
__invoke()参数只能是$passable和$next - 测试时别 mock 整个 pipeline,而是单独测每个 pipe 的行为——它们本该是纯逻辑单元










