作者 🐼
wolfcode
人生一场虚空大梦,韶华白首,不过转瞬。惟有BUG恒在,往复循环,不曾更改。
# PHP 8.6 特性和功能提前预览
PHP 的年度大版本即将到来—— **PHP 8.6 正式版将于 2026年11月19号发布**。
目前它已经进入 Beta 测试阶段;9 月 22 号将执行功能冻结,两天后发布第一个 RC 候选版本。
## 核心新特性预览
### 1. 部分函数应用(Partial Function Application, PFA)
部分函数应用允许预先填充一部分函数参数,返回一个接收剩余参数的闭包。`?` 代表后续传入单个参数占位符;`...` 代表剩余全部参数。
```php
$makeSlug = str_replace(' ', '-', ?);
$makeSlug('Hello World'); // Hello-World
$titles = array_map(strtolower(?), $titles);
```
- 生成的闭包会完整保留原函数的参数名、类型声明与默认值。
- 预先传入的参数在生成偏函数时求值,而不是调用闭包的时候才求值。
- **配套规定**:每一个 `?` 占位符,在生成的闭包上都会成为必传参数,即便原函数的该参数是可选参数。
- *注:该提案旧版本 2021 年被否决;第二版 RFC 以 33 票赞成、0 票反对获得通过。*
### 2. clamp() 函数族
新增 `clamp()`:如果传入值落在最小 / 最大区间内,则直接返回原值;超出边界则返回距离最近的边界值。
```php
clamp(10, min: 0, max: 100); // 10
clamp(101, min: 0, max: 100); // 100
clamp(-1, min: 0, max: 100); // 0
```
- 支持所有可比较类型,包含字符串、DateTime 对象。
- 如果传入的最小值大于最大值,会抛出 ValueError。
- 该函数用来替代广为使用但容易写反的写法:`min(max($value, $min), $max)`。
### 3. Duration 时间时长类
PHP 8.6 新增 `Time\Duration`,这是一个 `final readonly` 类,用于表示秒表式时间长度,支持纳秒精度。提供各时间单位的工厂方法、算术运算方法,同时支持比较运算符。
```php
use Time\Duration;
$oneSecond = Duration::fromSeconds(1);
$halfSecond = $oneSecond->divideBy(2);
$total = $oneSecond->add($halfSecond);
$delay = Duration::fromMilliseconds(100)->multiplyBy(2 ** $attempt);
$total > $delay; // 可直接使用比较运算符
```
- 也可以通过 ISO 8601 时长字符串构建实例。
- 该类作为标准类型,供内核与新的轮询 API 接收使用,替代松散的整数、浮点数时间值。
### 4. 只读属性支持默认值
PHP 8.6 起,`readonly` 属性可以设置默认值。8.6 版本之前,这么写属于编译错误;这让实现 PHP 8.4 只读接口属性时,写固定默认值非常别扭。
```php
final readonly class CreateBooksTable implements Migration {
public string $name = '2026_01_01_create_books_table';
}
```
- RFC 仅移除语法限制;readonly 语义不变,初始化之后依旧不能重新赋值。
### 5. 函数参数直接书写文档注释
现在可以直接给参数写文档注释,`ReflectionParameter::getDocComment()` 可以读取该注释。不再需要在函数上方的 `@param` 标签重复写参数名称。
```php
function search(
/** Terms to search for in the database */
string $query,
/** Maximum number of entries to return */
int $limit = 10,
): array {
// ...
}
```
- 静态分析工具与 IDE 可以直接读取参数上的注释。
### 6. Polling(轮询)API
全新命名空间 `Io\Poll`,为 PHP 提供统一封装的 IO 多路复用接口:Linux 下 epoll、BSD/macOS 下 kqueue、Solaris event ports、Windows WSAPoll。对于用户态实现事件循环、异步运行时的开发者,可以用来替代旧的 `stream_select()`。
```php
use Io\Poll\{Context, Event, StreamPollHandle};
$poll = new Context();
$server = stream_socket_server('tcp://0.0.0.0:8080');
stream_set_blocking($server, false);
$poll->add(new StreamPollHandle($server), [Event::Read], ['type' => 'server']);
while (true) {
foreach ($poll->wait(1) as $watcher) {
if ($watcher->hasTriggered(Event::Read)) {
// accept the connection
}
}
}
```
- 该 API 首要目标服务 PHP 内部(例如信号处理、FPM 改进);其次供用户态异步框架使用。
### 7. SortDirection 枚举
内置全局枚举 `SortDirection`,包含 `Ascending`(升序)、`Descending`(降序)两个 case。
```php
$query->orderBy('created_at', SortDirection::Descending);
```
- 目的是提供统一标准类型,避免各个类库各自定义排序枚举,查询构建器是典型使用场景。
### 8. 流(Stream)统一错误处理模型
流增加统一错误模型。新增 `error_mode` 上下文选项,可选:警告、抛出异常、静默;`stream_last_errors()` 返回结构化 `StreamError` 对象,获取上一次操作的错误。
```php
$context = stream_context_create([
'stream' => ['error_mode' => StreamErrorMode::Exception],
]);
try {
$stream = fopen('/nonexistent/file.txt', 'r', false, $context);
} catch (StreamException $e) {
foreach ($e->getErrors() as $error) {
echo $error->code->name . ': ' . $error->message;
}
}
```
- `StreamErrorCode` 枚举定义超过 50 个语义化错误码。
### 9. URI 扩展增强(PHP 8.5 延续改进)
PHP 8.5 引入的 URI 扩展,新增 Builder 构建器类。无需创建大量中间对象,即可组装 URI。
```php
$uri = new Uri\Rfc3986\UriBuilder()
->setScheme('https')
->setHost('example.com')
->setPath('/foo/bar')
->build();
```
### 10. Session 会话安全默认值变更
全新安装环境下,php.ini 三个 session 配置项更新默认值:
| 配置项 | 旧默认值 | 新默认值 |
| --- | --- | --- |
| `session.use_strict_mode` | `0` | `1` |
| `session.cookie_httponly` | `0` | `1` |
| `session.cookie_samesite` | 未设置 | `Lax` |
---
> **结语**:PHP 8.6 在发布前一定还会有变化,但可以预知的是会带给开发者更多惊喜。