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

相关推荐
两个人的幸福10 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
BingoGo12 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack12 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户30745969820713 天前
PHP 扩展——从入门到理解
php
鹏仔先生14 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
云水一下14 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
xingpanvip14 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
酉鬼女又兒14 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php
dog25014 天前
不要再继续优化 TCP
网络协议·tcp/ip·php
Channing Lewis14 天前
PHP 解析 Excel 的那些坑:一次“行号错位”引发的数据丢失
开发语言·php·excel