代码 PHP 8.6 的 Stream 错误 API:从猜 warning 文本到读 StreamErrorCode

2026-11-15 21:05:15

PHP 8.6 的 Stream 错误 API:从猜 warning 文本到读 StreamErrorCode

PHP 8.6 给 Stream API 加了一套统一的错误模型:错误模式、错误类型和异常都收进同一套结构里,不再只有一条 warning 字符串。这套 API 是 opt-in 的,不配置时行为与旧版本一致。

新增的类与函数

  • StreamError、StreamException 两个类
  • StreamErrorStore、StreamErrorMode、StreamErrorCode 三个枚举
  • stream_last_errors()、stream_clear_errors() 两个函数

行为由流上下文选项 error_mode、error_store、error_handler 控制。error_mode 决定错误怎么落地,在「维持 warning / 抛异常 / 静默」三者之间选;error_store 用来把错误攒在流上下文里,事后再读;error_handler 则把错误的处理交给调用方自己的回调。

取错误

错误模式选「抛异常」时,失败会以 StreamException 的形式抛出;选另外两种时,可以从 store 里把结构化错误取出来:

// error_mode 取 StreamErrorMode 里「抛异常 / 维持 warning / 静默」对应的成员
// error_store 传一个 StreamErrorStore 实例
$context = stream_context_create([
'error_mode'  => $mode,
'error_store' => $store,
]);

try {
$fh = fopen('https://example.com/data.json', 'rb', false, $context);
} catch (StreamException $e) {
// 抛异常模式下走这里
}

$errors = stream_last_errors();
foreach ($errors as $error) {
// $error 是 StreamError,带一个 StreamErrorCode 枚举
// 具体成员名以 8.6 发布版为准,这里按语义分支
switch ($error->code) {
// case StreamErrorCode:::   ...
// case StreamErrorCode:::   ...
// case StreamErrorCode::: ...
}
}

stream_clear_errors();

stream_clear_errors() 用于清掉当前攒下的错误,避免一次请求里多次打开流时错误互相污染。

排错时到底省了什么

以前 fopen()、file_get_contents()、stream_socket_client() 失败,能拿到的只有 error_get_last() 里的一段文本,或者被 @ 压掉的 warning。要区分「连不上主机」「TLS 握手失败」「php://filter 串了太多层过滤器」,只能对 warning 文本做字符串匹配,脆弱且依赖措辞。

有了 StreamErrorCode 之后,这几种情况可以直接按枚举分支处理,不必再解析文案;异常模式下还能顺带拿到调用栈。

php://filter 的过滤器数量上限

同一个版本还给 php://filter URL 加了 filter.max_filter_count 上下文选项。设置之后,如果这个 URL 会追加的过滤器数量超过配置值,打开流直接失败并给出 warning;传负值则关闭这项检查。

$context = stream_context_create([
'filter' => [
'max_filter_count' => 16,
],
]);

// 过滤器链过长的 php://filter URL 会在这里失败
$fh = fopen('php://filter/read=string.toupper/resource=/tmp/a.txt', 'rb', false, $context);

对接受用户可控的过滤器链的代码来说,这是一个现成的上限,不用自己数 / 分隔的过滤器段。

兼容性

整套 API 是 opt-in:不设 error_mode 时仍是老行为,warning 照旧,stream_last_errors() 也不会凭空多出东西。库如果想同时支持 8.6 和更早的版本,先探测类是否存在,再决定走结构化错误还是回落到 error_get_last():

if (class_exists('StreamError')) {
// PHP 8.6+:配置 error_mode / error_store,按 StreamErrorCode 分支
} else {
// 旧版本:error_get_last() + warning 文本
}

版本

PHP 8.6 GA 计划于 2026-11-19,最新预发布为 8.6.0RC7(2026-11-12)。上面的代码按公告整理,未在 RC 上实测;枚举成员名请以最终发布版为准。

复制全文 生成海报 PHP 流处理 排错

推荐文章

程序员茄子在线接单