Hyperf 在纯 Windows 下可运行 Swow,但需严格匹配 PHP≥8.1、Swow 扩展(如 v1.4.4)、hyperf/swow-driver(如 ^3.1.18)三者版本,禁用 opcache.enable_cli=1,使用 swow-skeleton 创建项目,配置 heartbeat_idle_time=60 等心跳参数,并清空 runtime/container 缓存后启动。

Hyperf 在纯 Windows 环境下跑 Swow 是可行的,但必须严格匹配 PHP、Swow 扩展、hyperf/swow-driver 三者版本,缺一不可;否则启动直接报 Class 'Swow\Socket' 不存在或 Server start failed: Unknown option。
确认 PHP 和 Swow 扩展已就位
Swow 不依赖 WSL,但要求 PHP ≥ 8.1(Hyperf 3.2+ 已弃用 8.0),且必须启用 sockets、pcntl、posix 等 CLI 必需扩展。Swow 扩展不能靠 pecl install swow 一键搞定——Windows 上需用预编译包或 VS 编译,Linux/macOS 可用 pecl 或源码编译。
- 运行
php --ri swow,检查输出中Version行是否为v1.4.4(Hyperf 3.1.x 最稳)或v1.5.1(仅测试可用) - 若提示
Extension 'swow' not present,说明扩展未加载:检查php.ini是否含extension=swow,路径是否正确(如extension=C:\php\ext\php_swow.dll) - 禁用
opcache.enable_cli=1,否则热重载会失效甚至进程僵死
用 swow-skeleton 创建项目,别混用 swoole-skeleton
Hyperf 官方提供两个骨架:hyperf/hyperf-skeleton 默认绑 Swoole,hyperf/swow-skeleton 才预置 Swow 驱动和配置。强行在 swoole-skeleton 里改 driver => 'swow' 会漏掉关键 autoload 和事件监听器。
- 执行
composer create-project hyperf/swow-skeleton,过程跳过所有可选组件(直接回车),避免引入不兼容监听器 - 创建后立刻检查
composer.json中是否含"hyperf/swow-driver": "^3.1.18"(对应 Swow v1.4.4)或"dev-main"(对应 v1.5.1) - 若已有项目,先
composer remove hyperf/swow-driver,再按 Swow 版本重装驱动,不能跳过这步
server.php 和 socketio.php 必须手动调心跳参数
Swow 的默认心跳(10s ping + 5s timeout)和 Hyperf 的 SocketIO 实现冲突,会导致连接被底层静默断开,上层还往已关闭 socket 写数据,抛出 Broken pipe 或返回 null。
- 在
config/autoload/server.php的'swow'服务器配置块中加:'settings' => ['heartbeat_idle_time' => 60, 'heartbeat_check_interval' => 25] - 同时在
config/autoload/socketio.php中设'ping_interval' => 0,关掉 Hyperf 自己的心跳,让 Swow 统一管 - 不改这两处,哪怕服务能起来,WebSocket 连接也会在 15 秒左右异常断开
启动前清 runtime 缓存并验证扩展加载顺序
Hyperf 启动时会扫描扩展并生成容器定义,Swow 扩展必须在 hyperf/swow-driver 加载前就绪,否则 Container 构建失败,报错信息模糊(如 Call to undefined method Swow\Coroutine::defer())。
- 每次换 Swow 版本或重装 driver 后,务必执行:
rm -rf runtime/container/ runtime/cache/ - 启动前用
php -m | findstr swow(Windows)或php -m | grep swow(Linux/macOS)确认扩展已列在模块列表首位 - 运行
php bin/hyperf.php start,成功日志末尾应出现Server started: http://127.0.0.1:9501 [swow],不是[swoole]
Swow 环境最易被忽略的是驱动包与扩展的隐性绑定——它们不是语义化版本兼容,而是方法签名级硬依赖。哪怕只差一个小版本,setOption() 参数个数变化就足以让整个服务起不来。动手前先 php --ri swow 和 composer show hyperf/swow-driver 对齐版本,比反复重启有效得多。


















