PHP 8.6 即将支持部分函数应用
你有没有遇到过这种情况:明明只是想写个简单的回调,结果却写成了一篇小作文——箭头函数里塞满了类型声明、参数重排,还有一堆样板代码,就为了传一个值?
好消息是,PHP 8.6 将引入部分函数应用(Partial Function Application),让我们的日子好过一些。
原文链接 PHP 8.6 即将支持部分函数应用
什么是部分函数应用?
PHP 8.6 的部分函数应用允许你通过调用函数时传入部分参数,并用占位符表示剩余参数,来创建一个"预配置"的 callable。PHP 不会立即执行函数,而是返回一个 Closure,其参数列表会根据缺失的部分自动推导。
占位符有两种:
- ? 表示"这里需要一个参数"
- ... 表示"转发所有剩余参数"
来看一个基本示例:- 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 的扩展。
多个占位符
你可以留多个"坑":- $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
复制代码 用 ... 表示"剩下的全部"
- $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 会帮你搞定剩下的。- $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 对管道操作符也很友好:- $foo
- |> array_map(strtoupper(...), ?)
- |> array_filter(?, is_numeric(...));
- // 管道右侧需要一个一元 callable;PFA 可以简洁地提供
复制代码 命名参数与顺序
- 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)
复制代码 可变参数函数
- 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 函数:- function expensive(int $a, int $b, Point $c) { /* 耗时操作 */ }
- // 预填所有参数,延迟执行:
- $thunk = expensive(3, 4, $pt, ...); // 零必需参数的 Closure
- // 之后再执行:
- $result = $thunk();
复制代码 构造函数的限制
你不能对构造函数(new)使用部分应用。可以用静态方法或工厂函数代替:- $maker = Widget::make(?, size: 10); // OK
- $new = new Widget(?, 10); // 编译错误
复制代码 实际案例
来看一个更实用的例子:给 HTTP 请求添加 header。我们可以预填 header 名称和值,把请求数组留到后面再传:- 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。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |