欢迎访问晨星博客!
在 WordPress 插件或主题中处理第三方 API 返回的数据时,常见的流程是:先对原始数组进行参数校验 → 对字段进行格式化(如 trim、strtolower) → 最后组装成业务层使用的 DTO(数据传输对象)。传统写法往往会出现层层嵌套的函数调用,阅读时需要从最里层往外层逐步追踪,代码审查也容易遗漏细节。下面通过一个真实的接口转换例子,展示如何使用 PHP 8.5 引入的管道操作符 |> 将这些步骤线性化,提高可读性和维护效率。

下面是一段典型的 WordPress 插件代码,负责把用户提交的表单数据转成 UserDto 对象。为了保证每一步的结果都符合预期,开发者往往使用临时变量或深层嵌套调用:
function build_user_dto(array $payload): UserDto
{
// 参数校验
$email = $payload['email'] ?? '';
$name = $payload['name'] ?? '';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
// 格式化
$email = strtolower(trim($email));
$name = trim($name);
$name = ucwords(strtolower($name));
// 组装 DTO
return new UserDto(
email: $email,
name: $name,
createdAt: new DateTimeImmutable(),
);
}
虽然功能完整,但阅读时需要在不同的代码块之间来回跳,尤其在业务逻辑更复杂、需要多次清洗、过滤时,嵌套会更深,审查成本随之上升。
借助 |>,我们可以把上述步骤串成一条“流水线”,每一步的返回值直接作为下一步的输入。代码结构更像自然语言的顺序,阅读时从左到右即可把握全局:
function build_user_dto(array $payload): UserDto
{
return $payload
|> (fn (array $p) => $p['email'] ?? '')
|> (fn (string $email) => filter_var($email, FILTER_VALIDATE_EMAIL)
? $email
: throw new InvalidArgumentException('Invalid email'))
|> (fn (string $email) => strtolower(trim($email)))
|> (fn (string $email) => ['email' => $email, 'name' => $payload['name'] ?? ''])
|> (fn (array $data) => $data['name'] = ucwords(strtolower(trim($data['name'] ?? '')))
? $data
: $data)
|> (fn (array $data) => new UserDto(
email: $data['email'],
name: $data['name'],
createdAt: new DateTimeImmutable(),
));
}
可读性提升
管道链中的每个函数都可以返回任意类型,但如果某一步抛出异常,后续的调用会被中断,这与传统写法的 if 检查效果相同。值得注意的细节包括:
使用 throw 表达式(PHP 8.0+)可以直接在管道中抛出错误,保持链式结构不被破坏。
为每个匿名函数添加参数和返回类型,可让 PHPStan、Psalm 等工具在编译阶段捕获类型不匹配。例如 fn (string $email): string => strtolower($email) 明确表明输入输出都是字符串。
管道左侧的返回值始终是按值传递,若需要修改引用对象,建议在链式前使用 clone 或显式的引用函数,避免意外副作用。
如 PHPStan 文档所示,使用管道时箭头函数必须加括号:5|>(fn($x)=>$x*2) 否则会被解析为语法错误。
array_filter、array_map、array_reduce 等组合。filter_var、自定义校验函数逐层检查输入合法性。不适合的情况包括需要跨步骤共享大量中间状态(如一次循环中产生多组不同的数据结构),此时仍建议使用显式的临时变量或专门的类来封装状态。
假设我们在一个 WordPress 插件中已有如下函数,用于把订单原始数据转成 OrderDto:
function transform_order(array $raw): OrderDto
{
$items = array_map('intval', $raw['items']);
$total = array_sum($items);
if ($total <= 0) {
throw new RuntimeException('Invalid total');
}
$currency = strtoupper(trim($raw['currency'] ?? 'usd'));
return new OrderDto($items, $total, $currency);
}
**步骤 1:抽取每一步为
声明:原创文章请勿转载,如需转载请注明出处!