PHP Fiber设计 suspend 与 resume 的值传递的实现方法
来源:17golang原创
时间:2026-09-15 20:35:11 366浏览 收藏
PHP Fiber 最容易混淆的不是“怎么暂停”,而是一次调用里有三种不同的值:suspend() 交给外部的值、resume() 送回暂停点的值,以及 Fiber 结束后 getReturn() 读取的最终结果。把这三段协议分开,生命周期就不会乱。
官方地址:https://www.php.net/manual/en/language.fibers.php
start()或resume()的返回值,表示 Fiber 当前一次暂停交出的值。resume($value)的参数会成为 Fiber 内部当前suspend()调用的返回值。- 只有
isTerminated()为真时才读取getReturn();它不是中间暂停值的替代品。
先把 Fiber 的三段值协议拆开
排查 Fiber 时,可以先把调用方向画成两条线。Fiber 执行到 Fiber::suspend('need-input'),外部的 start() 会拿到 need-input;外部随后调用 resume('approved'),Fiber 内部暂停的那一行会得到 approved。如果闭包最后执行 return 'done',这个结果要等 Fiber 终止后通过 getReturn() 取出。

用两次 suspend 观察恢复点到底收到什么
下面的示例故意设置两个暂停点。第一个 start() 只负责让 Fiber 运行到第一处暂停;第一个 resume() 的参数回到第一处 suspend();第二处暂停则把新的中间值交给下一次 resume()。代码中的注释只标出值的方向,避免把中间结果和最终结果混在一起。
继续计算”的值协议。
$fiber = new Fiber(function (): string {
// start() 会拿到这里交出的 need-user 值。
$user = Fiber::suspend('need-user');
// resume() 的参数成为上一行 suspend() 的返回值。
$token = Fiber::suspend('need-token:' . $user);
// return 是终止结果,只能在 Fiber 结束后用 getReturn() 读取。
return 'authorized:' . $token;
});
$first = $fiber->start();
echo $first, PHP_EOL; // need-user
// 只有暂停状态才能 resume;这里的返回值是下一次 suspend() 的值。
$second = $fiber->resume('alice');
echo $second, PHP_EOL; // need-token:alice
// 继续执行到 return,Fiber 终止;此处返回 null 很正常。
$fiber->resume('token-7');
// 终止后才能取得闭包的最终 return 值。
echo $fiber->getReturn(), PHP_EOL; // authorized:token-7
?>
这里的关键观察是:第二次 resume() 没有返回 authorized:token-7,因为它只是把 Fiber 推到终点;最终结果属于 getReturn()。如果把业务结果误读成 resume() 的返回值,调度器就会提前结束或把 null 当成业务失败。
状态检查决定调用是否有效
resume() 只接受 suspended 状态。Fiber 尚未启动时要调用 start(),正在运行时不能从外部再次切入,已经终止后也不能继续 resume()。因此调用方最好把状态和动作放在同一处处理,而不是在多个回调里凭经验调用。
| 状态 | 可用动作 | 值的含义 |
|---|---|---|
| 未启动 | start($args...) | 返回首个 suspend 交出的值;若直接结束则返回 null |
| 已暂停 | resume($value) 或 throw($e) | 参数回到当前 suspend;返回下一次 suspend 的值 |
| 已终止 | getReturn() | 读取闭包最终 return |

如果外部输入代表失败,而不是正常恢复值,可以用 throw() 把异常送入暂停点;Fiber 内部是否捕获它由业务决定。若异常没有被处理,Fiber 不会产生可读取的正常返回值,调用方应在异常边界记录失败,而不是继续调用 getReturn()。
把值协议写进调度器的检查清单
- 为每个暂停点命名协议:外部看到什么值、恢复时需要什么值。
- 把
start()的首个输入和resume()的恢复输入分开记录,避免同名变量掩盖方向。 - 用
isSuspended()判断是否允许恢复,用isTerminated()判断是否允许读取最终结果。 - 让正常结果走
return/getReturn(),让取消或失败走throw()和异常处理。
Fiber 只提供可中断的执行栈,不替你定义事件循环、超时策略或资源清理。设计时先固定值的方向,再把调度器接入外部 IO,问题会比“先写一个万能协程包装器”少很多。
相关问题
resume() 为什么有时返回 null?
当这次恢复直接让 Fiber 执行到 return 或异常结束时,没有下一处 suspend 可交出值,resume() 返回 null 并不等于业务结果为空。
getReturn() 能不能在 suspend 状态读取?
不能。Fiber 尚未终止、尚未启动或异常终止时,getReturn() 都不应被当作中间结果读取入口。
Fiber::suspend() 能否在 Fiber 外调用?
不能。它依赖当前 Fiber;在 Fiber 外调用会抛出 FiberError。
-
312 收藏
-
231 收藏
-
129 收藏
-
443 收藏
-
106 收藏
-
206 收藏
-
文章 · php教程 | 2小时前 | HTTP · 文件流 · 元数据 · wrapper · php教程 · PHP Stream · stream_get_meta_data PHP Stream stream_get_wrappers HTTP wrapper 文件流识别217 收藏
-
文章 · php教程 | 5小时前 | tcp连接 · php教程 · stream_socket_client · DNS排查 · 网络故障诊断 · PHP stream_socket_client 超时 PHP DNS 解析失败 PHP TCP 连接拒绝 stream_socket_client errno PHP 网络连接排查395 收藏
-
132 收藏
-
175 收藏
-
162 收藏
-
402 收藏
-
418 收藏
-
229 收藏
-
384 收藏
-
文章 · php教程 | 15小时前 | PHP · 日期处理 · 兼容性 · DatePeriod · 时间区间 · php DateTime DateInterval DatePeriod INCLUDE_END_DATE 日期周期434 收藏
-
496 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习