代码 PHP 8.6 部分函数应用:`add(1, ?)` 拿到的是一个闭包

2026-11-11 21:01:21

PHP 8.6 部分函数应用:add(1, ?) 拿到的是一个闭包

PHP 8.6 加入了部分函数应用(Partial Function Application,PFA)。语法上只有两个占位符:? 替换一个参数,... 替换剩下的全部参数;这样的调用会返回一个闭包(Closure),由它接收那些没有被预填的参数。

strtolower($t)`。

## 三条语义细节

**预填参数在创建时求值,不在调用时求值。** `$a = 1; $f = add($a, ?); $a = 2;` 之后 `$f(5)` 仍然是 `6`,因为 `$a` 的值在 `add($a, ?)` 执行的那一刻就已经确定下来了。

**返回的闭包保留原函数的参数名、类型和默认值。** 反射、命名参数、类型检查看到的都是原函数的签名,而不是一个匿名的 `$arg1`。

**每个 `?` 在闭包上都变成必填参数**,即使原参数本来可选——这是后续 RFC 明确下来的。比如 `add` 的 `$c` 有默认值 `0`,但 `$f = add(1, 2, ?);` 生成的闭包必须传第三个参数,`$f()` 直接抛 `ArgumentCountError`。

**内部函数同样可用**,`str_replace`、`strtolower` 这些不需要任何特殊处理,因为它们走的是同一套调用约定。

## 从被否到全票通过

这个提案 2021 年的旧版本被否掉了;v2 版本以 33:0 通过。PHP 8.6 的 GA 计划日期是 2026 年 11 月 19 日。

- 项目:
- RFC:Partial Function Application v2

## 取舍:什么时候比 arrow fn 好

值得用 `?` 的场景通常是**参数位置深、只需要固定其中一个**:`str_replace` 的第三个参数、`preg_replace` 的 `$subject`、某个方法的第二三个入参。这时 arrow fn 要重复声明参数名和类型,`?` 只是把一个位置空出来,噪音更少。作为 callback 直接内联时也一样,`array_map(strtolower(?), $titles)` 比多一层 `fn` 更接近“我要的就是这个函数,只是参数少一个”。

反过来,**`?` 本身不携带任何语义**。读者看到一个 `?`,必须回查原函数签名才知道它对应哪个参数、是什么类型;一个表达式里嵌套两个 partial 时,`?` 的归属更容易看错。`...` 的问题类似:闭包到底要几个参数,在定义处完全看不出来,只能去数原函数剩下的形参。arrow fn 虽然啰嗦,但参数名本身就是文档。

一个粗糙的判据:原函数签名短、参数含义一眼能看出来(`strtolower`、`add`),用 `?`;参数多、类型相近、或者固定的是中间某个位置,老老实实写 arrow fn,把名字写出来。
复制全文 生成海报 PHP 8.6 闭包 函数式

推荐文章

程序员茄子在线接单