swoole_event_add 是初始化注册,swoole_event_set 仅用于已添加 fd 的动态调整;必须先 add 再 set,否则返回 false 且无提示;set 不释放回调,需配对 del 才能清理资源。

swoole_event_add 和 swoole_event_set 都是向 Swoole 事件循环注册或调整文件描述符(fd)监听行为的函数,但它们的语义、触发条件和使用前提完全不同——直接混用会导致回调不执行、事件丢失,甚至 false 返回却无报错。
必须先 swoole_event_add 才能调用 swoole_event_set
swoole_event_set 不是独立注册函数,它只作用于“已在 Reactor 中存在”的 fd。如果该 fd 从未被 swoole_event_add 添加过,调用 swoole_event_set 会直接返回 false,且不抛异常、不提示原因。
- 常见错误现象:
swoole_event_set($fd, $cb, null, SWOOLE_EVENT_READ)返回false,但你以为只是参数写错了,实际是漏了前置的swoole_event_add - 验证方式:调用前可用
swoole_event_exist($fd)检查(Swoole v4.8+ 支持),v4.7 及更早需自行维护 fd 状态映射表 - 注意:即使你用
fopen或stream_socket_client创建了资源,也必须显式swoole_event_add后才进入事件循环生命周期
swoole_event_add 是初始化,swoole_event_set 是动态调整
swoole_event_add 完成三件事:注册 fd 到 epoll/kqueue、设置初始回调、启用指定事件掩码;而 swoole_event_set 只做两件事:替换回调函数(仅当传入非 null)、开关事件监听(通过 $flags 参数)。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 关键差异:
swoole_event_add的$write_callback和$event_flag是必填逻辑的一部分;swoole_event_set中对应参数为null表示“不修改”,不是“清空” - 典型场景:MySQL 异步查询后,先用
swoole_event_add监听可读,等reap_async_query完成后,用swoole_event_set($fd, null, null, SWOOLE_EVENT_WRITE)切换为监听可写,准备下一次 query - 陷阱:
swoole_event_set($fd, null, null, SWOOLE_EVENT_READ)不会清除旧回调,只是关闭可写、开启可读——旧read_callback依然有效
回调函数不会被 swoole_event_set 释放
无论你传多少次 null 给 $read_callback 或 $write_callback,只要没调用 swoole_event_del,PHP 层的回调 zval 就一直被引用,内存不会释放,闭包捕获的变量也会持续存活。
- 后果:长连接场景下反复
swoole_event_set替换回调但不del,可能引发内存缓慢增长 - 正确做法:明确生命周期时,在不再需要监听该 fd 时,必须配对调用
swoole_event_del($fd) - 注意:
swoole_event_del会同时释放读/写回调,并从 Reactor 中移除 fd;它不关心你之前调了多少次set
最易被忽略的一点:事件掩码($flags)和回调函数是解耦的。你可以只改掩码不改回调,也可以只改回调不改掩码,但一旦掩码里不含 SWOOLE_EVENT_READ 却设置了 $read_callback,这个回调永远不会被触发——Swoole 底层只按掩码投递事件,不校验回调是否存在。










