PHP 8.6 即将支持部分函数应用

PHP 8.6 即将支持部分函数应用

你有没有遇到过这种情况:明明只是想写个简单的回调,结果却写成了一篇小作文------箭头函数里塞满了类型声明、参数重排,还有一堆样板代码,就为了传一个值?

好消息是,PHP 8.6 将引入部分函数应用(Partial Function Application),让我们的日子好过一些。

原文链接 PHP 8.6 即将支持部分函数应用

什么是部分函数应用?

PHP 8.6 的部分函数应用允许你通过调用函数时传入部分参数,并用占位符表示剩余参数,来创建一个"预配置"的 callable。PHP 不会立即执行函数,而是返回一个 Closure,其参数列表会根据缺失的部分自动推导。

占位符有两种:

  • ? 表示"这里需要一个参数"
  • ... 表示"转发所有剩余参数"

来看一个基本示例:

php 复制代码
function add4(int $a, int $b, int $c, int $d): int 
{
    return $a + $b + $c + $d;
}

// 先填一部分,留一个以后再传:
$f = add4(1, ?, 3, 4);
// 等价于:
$f = static fn(int $b): int => add4(1, $b, 3, 4);

echo $f(2); // 1+2+3+4 = 10

如你所见,我们通过部分应用 add4 函数创建了一个新的 callable $f,传入了部分参数,用占位符表示缺失的参数。之后调用 $f 并传入剩余参数就能得到最终结果。

你也可以把 PFA 看作是 first-class callable 的扩展。

多个占位符

你可以留多个"坑":

php 复制代码
$f = add4(1, ?, 3, ?);
// 等价于:
$f = static fn(int $b, int $d): int => add4(1, $b, 3, $d);

echo $f(5, 7); // 1+5+3+7 = 16

... 表示"剩下的全部"

php 复制代码
$f = add4(1, ...);
// 等价于:
$f = static fn(int $b, int $c, int $d): int => add4(1, $b, $c, $d);

echo $f(2, 3, 4); // 10

有了 PFA,回调变得简洁且意图明确。不用再写一堆样板箭头函数来重排或固定参数了。只需在需要的地方放上 ?...,PHP 会帮你搞定剩下的。

php 复制代码
$strings = ['hello world', 'hello there'];

// 没有 PFA(啰嗦):
$result = array_map(static fn(string $s): string => str_replace('hello', 'hi', $s), $strings);

// 有了 PFA:
$result = array_map(str_replace('hello', 'hi', ?), $strings);
// 每个元素会被传入 $subject 位置的 ? 占位符

与管道操作符配合

PFA 对管道操作符也很友好:

php 复制代码
$foo
  |> array_map(strtoupper(...), ?)
  |> array_filter(?, is_numeric(...));
// 管道右侧需要一个一元 callable;PFA 可以简洁地提供

命名参数与顺序

php 复制代码
function stuff(int $i, string $s, float $f, Point $p, int $m = 0): string { /* ... */ }

// 命名参数乱序也没问题:
$c = stuff(?, ?, f: 3.5, p: $point);
// Closure 期望 (int $i, string $s)

// 命名占位符可以定义自己的参数顺序:
$c = stuff(s: ?, i: ?, p: ?, f: 3.5);
// Closure 期望 (string $s, int $i, Point $p)

可变参数函数

php 复制代码
function things(int $i, ?float $f = null, Point ...$points) { /* ... */ }

// 保持可变参数开放:
$c = things(1, 3.14, ...);
// Closure 期望 (Point ...$points)

// 强制固定数量(可变参数变成必需的槽位):
$c = things(?, ?, ?, ?);
// Closure 期望 (int $i, ?float $f, Point $points0, Point $points1)

Thunk 函数

用 PFA 可以轻松实现 Thunk 函数:

php 复制代码
function expensive(int $a, int $b, Point $c) { /* 耗时操作 */ }

// 预填所有参数,延迟执行:
$thunk = expensive(3, 4, $pt, ...); // 零必需参数的 Closure

// 之后再执行:
$result = $thunk();

构造函数的限制

你不能对构造函数(new)使用部分应用。可以用静态方法或工厂函数代替:

php 复制代码
$maker = Widget::make(?, size: 10); // OK
$new = new Widget(?, 10);           // 编译错误

实际案例

来看一个更实用的例子:给 HTTP 请求添加 header。我们可以预填 header 名称和值,把请求数组留到后面再传:

php 复制代码
function addHeader(array $req, string $name, string $value): array 
{
  $req['headers'][$name] = $value; 
  
  return $req;
}

// 请求数组留空;预填 header 名称/值
$withAuth = addHeader(?, 'Authorization', 'Bearer TOKEN');

$req = ['url' => '/me', 'headers' => []];
$req = $withAuth($req);

这样我们就创建了一个可复用的 callable $withAuth,它可以给任何传入的请求数组添加 Authorization header。

常见 PFA 模式

以下是一些与 PFA 相关的常用模式:

  • 一元回调array_map(in_array(?, $allowed, strict: true), $input)
  • 从左填充,剩余留空stuff(1, 'two', ...)
  • 命名参数设置,剩余留空stuff(f: 3.14, s: 'two', ...)
  • First-class callable(退化情况)func(...)

总结

部分函数应用将是 PHP 8.6 的一个强大新特性,在处理回调时可以显著减少样板代码并提高代码清晰度。通过允许你用占位符预配置函数,PFA 让创建简洁、意图明确的 callable 变得轻而易举,不再需要冗长的箭头函数。

更多关于部分函数应用的信息,请阅读官方 RFC

相关推荐
颜酱15 分钟前
# 02 | 搭骨架:用 LangGraph 编排 12 步工作流(思路)
前端·人工智能·后端
颜酱16 分钟前
02 | 搭骨架:用 LangGraph 编排 12 步工作流
前端·人工智能·后端
嘉伟桑1 小时前
Python调用电价API返回JSON示例:分时电价、现货电价和字段解析
后端
武子康2 小时前
Shippy:确定性工具、会话级 Sandbox 与 Live-Data Eval(4 类收敛 + 7 步实现方案 + 6 类评测指标)
前端·人工智能·后端
我叫黑大帅2 小时前
我为什么单一消费者的场景下,要用 Redis List 当消息队列?
redis·后端·面试
AskHarries2 小时前
文件上传系统
后端
止语Lab3 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活3 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困3 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn3 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端