ReactPHP 的 loop 必须手动启动,不调用 run() 就无响应;HTTP 大请求体需调大 maxBuffer 或流式处理;子进程需绑定 error/exit 事件并加超时;Promise 不支持 await,须用 then()/done();禁止使用 sleep() 阻塞 loop。

ReactPHP 的 loop 必须手动启动,不调用 run() 就没反应
很多人写完 React\Http\Server 或 React\Socket\TcpServer 代码,浏览器一直转圈或直接超时——根本原因是忘了启动事件循环。ReactPHP 不是“注册完就自动跑”,它依赖显式调用 $loop->run() 才开始监听、分发、回调。
常见错误现象:php server.php 执行后立即退出,或者请求完全无响应;调试时打日志发现回调函数一次都没执行。
-
$loop实例通常来自React\EventLoop\Factory::create(),别自己 new - 所有异步操作(比如
$server->on('request', ...))必须在run()前注册好 - 一旦
run()开始,程序控制权就交给了 loop,后续代码不会继续执行(除非 loop 停止)
HTTP 请求体过大时,React\Http\Browser 默认会失败
用 React\Http\Browser 发起 POST 或上传请求,如果 body 超过约 2MB,大概率收到 Connection reset by peer 或直接卡死——这不是网络问题,而是底层 React\Stream\ReadableResourceStream 对大 buffer 的处理限制。
使用场景:调用第三方 API 传 JSON 数据、上传文件、批量同步数据。
立即学习“PHP免费学习笔记(深入)”;
- 临时解决:设置
maxBuffer选项,例如new Browser($loop, ['maxBuffer' => 10 * 1024 * 1024]) - 但更稳妥的做法是改用
React\Stream\WritableResourceStream分块写入,配合React\Http\Message\Request手动构造流式 body - 注意 PHP 的
memory_limit仍生效,大文件上传建议配合stream_copy_to_stream()避免全量加载到内存
React\ChildProcess\Process 启动后子进程意外退出,父进程收不到通知
用 React\ChildProcess\Process 执行 shell 命令(如 ffmpeg、node 脚本),有时子进程崩溃了,PHP 主程序却还在等 on('exit') 回调——结果就是 hang 住,run() 永远不返回。
根本原因:ReactPHP 默认只监听 SIGCHLD,但某些子进程(尤其带重定向或后台化行为的)可能绕过标准退出路径。
- 务必为每个
Process绑定on('error')和on('exit'),两者缺一不可 - 加超时保护:用
$loop->addTimer(30, function () use ($process) { $process->terminate(); }) - 避免在子进程中调用
exec &、nohup等脱离父进程控制的操作;需要后台运行请改用系统服务管理
协程风格写法在 ReactPHP 里不成立,别套用 async/await 思维
看到 React\Promise\Promise 就想写 await $promise?PHP 8.1+ 虽支持 async 函数,但 ReactPHP 的 Promise 不是原生协程 Promise,直接 await 会报 Cannot await a promise 错误,或静默失败。
性能影响:强行用 React\Async\async() 包裹反而增加调度开销,且无法和 loop 深度集成(比如 socket 超时、流暂停)。
- Promise 必须用
done()、then()、otherwise()链式处理,这是 ReactPHP 的约定 - 如果真要协程体验,换
Swoole或Amphp,ReactPHP 的设计哲学就是纯回调驱动 - 混合使用
sleep()、usleep()会阻塞整个 loop,绝对禁止
ReactPHP 的难点不在语法,而在彻底放弃“线性执行”预期——IO 操作没有返回值,只有回调时机;错误不抛出,只走 error 通道;超时、取消、重试都得自己配 loop timer 和状态机。稍不注意,逻辑就散落在十几个匿名函数里,比同步代码还难 debug。











