编程 PHP 8.6 软冻结:用 ? 占位符预填参数的 partial function application

2026-09-24 21:12:23

PHP 8.6 软冻结:用 ? 占位符预填参数的 partial function application

PHP 8.6 Beta 1 将于 2026 年 8 月 13 日(周四)发布,同时标记 soft feature freeze(phpnews.net/php-8-6-beta-1)。这个版本里对日常写代码影响最直接的一项,是 partial function application(部分函数应用):用一个 ? 占位符把函数的部分参数预先填好,返回一个闭包。

语法:? 占位符 + 剩余参数

调用时把要固定的实参写在原位置,不固定的位置放 ?,引擎返回一个 Closure,它只接收没被占位符占掉的那些参数。

function slugify(string $text, string $separator = '-'): string
{
    return strtolower(str_replace(' ', $separator, $text));
}

// 固定第二个参数,得到只接收 $text 的闭包
$slug = slugify(?, '_');

echo $slug('Hello PHP'); // hello_php

生成的闭包可以直接当回调传给 array_mapusort、事件监听器等需要 callable 的地方,不需要再包一层 fn()

和闭包、first-class callable 的区别

三种写法最终都得到 Closure,差别在参数是怎么来的。

// 1. 手写闭包:参数列表自己维护
$fn = fn(string $text) => slugify($text, '_');

// 2. first-class callable(PHP 8.1+):整体转发,参数一个都不能少
$fn = slugify(...);
$fn('Hello PHP', '_');

// 3. partial application(PHP 8.6):部分参数已固定
$fn = slugify(?, '_');
$fn('Hello PHP');
  • 手写闭包:最灵活,但被调函数的签名一变,闭包的参数列表要跟着改。
  • first-class callable slugify(...)(...) 表示"把整个可调用对象转成闭包",调用时仍要传全部参数,语义上是转发而非预填。
  • partial application:固定哪几个参数、剩下哪几个由原函数签名推导,调用方只需要关心剩下的参数。

8.6 一起锁定的其他特性

  • Io\Poll 命名空间下的轮询 API,可以用 epoll 或 WSAPoll 替代 stream_select()
  • Time\Duration 类,用于表示时长并做运算
  • readonly 属性默认值
  • 闭包优化:推导 static 并为引擎能证明相同的闭包做缓存(8.6 只落地了缓存部分,static 推导因为边界情况被放弃)
  • clamp(),把值限制在区间内
  • 更安全的会话默认值:session.use_strict_modesession.cookie_httponly 默认变为 1,session.cookie_samesite 默认变为 Lax
  • 类常量和枚举 case 上的 #[\Override]、枚举的 __debugInfo()、内置 SortDirection 枚举、函数参数的文档注释

时间线

阶段日期
Beta 1(soft freeze)2026-08-13
Beta 22026-08-27
Beta 32026-09-10
Hard feature freeze2026-09-22
RC12026-09-24
RC22026-10-08
RC32026-10-22
RC42026-11-05
GA2026-11-19

php.watch 上的语法与新函数变化

php.watch/versions/8.6 汇总的改动:

  • json_decode 的错误信息会指出出错位置
  • 新增 clamp 函数、SortDirection 枚举、grapheme_strrev
  • array_filter$mode 传入非法值时抛 ValueError
  • trim / ltrim / rtrim / chop 默认开始清理 Form-Feed(\f

Zend 博客补充的弃用项

zend.com/blog/php-8-6 提到 PHP 8.6 引入 Time\Duration(纳秒精度),同时确认了几项弃用:

  • 限制 filter chain 的最大数量(php://filter,新上限 16,可通过 filter.max_filter_count 配置)
  • 弃用 __construct() / __destruct() 的返回值
  • oniguruma 结束维护,所有 mbstring 正则函数(mb_ereg*mb_split)被弃用,将在 PHP 9.0 移除;对应 PECL 包 mb_onig 已创建,官方建议改用 PCRE 函数并加上 /u 修饰符

使用时注意的点

占位符只是位置标记,剩余参数按原签名顺序传入,所以用 ? 跳着填参数会让调用点难以阅读,这种场合手写闭包反而更清楚。partial application 生成的是真正的 Closure,可以直接进回调位置;但如果被调函数签名改了,预填的位置和剩余参数都会跟着变,编译期不会提醒你调用点是否还符合预期。

适用场景集中在"同一个函数反复用同一批前置参数":模板渲染里固定的转义/格式化函数、日志器上固定的 level、排序比较器里固定的字段名。只为单个调用点省一行 fn() 就没必要引入占位符语法了。

复制全文 生成海报 PHP 8.6 闭包 RFC

推荐文章

程序员茄子在线接单