yii2 官方不支持 websocket,需借助 workerman 等外部服务;yii2-workerman 仅为桥接扩展,协议处理、连接管理、广播逻辑等均由 workerman 承担,yii2 仅负责配置加载、模型调用与数据库操作。

WebSocket 在 Yii2 里不能直接用 yii\web\Socket
Yii2 官方不提供 WebSocket 支持,yii\web\Socket 根本不存在——这是常见误解的源头。你搜到的“Yii2 内置 WebSocket”基本是混淆了扩展名或误读文档。真要跑 WebSocket,得靠外部服务进程,Yii2 只负责配合握手、推送、状态管理。
workerman/yii2-workerman 扩展只是胶水,不是替代方案
这个扩展本质是把 Workerman 的事件循环和 Yii2 的生命周期做轻量桥接,它不接管 HTTP 请求,也不替换 Web 服务器。真正干活的是 Workerman\Worker 实例,Yii2 只用来加载配置、调用模型、查数据库。
-
yii2-workerman不处理 WebSocket 协议细节,比如帧解析、ping/pong、连接升级响应——全由 Workerman 底层完成 - 它默认只注册一个
onMessage回调,但你要做用户认证、房间管理、心跳续连,都得自己写逻辑,不能依赖 Yii2 的中间件或行为 - 启动命令是
php yii websocket/start,但实际执行的是Workerman\Worker::runAll(),和yii serve完全无关,别指望它能热重载控制器
连接鉴权必须在 onConnect 里手动做,且不能用 Yii2 Session
WebSocket 握手是独立于 HTTP 的 TCP 连接,$_SESSION 和 Cookie 在 onConnect 阶段不可用。常见错误是试图在回调里调 Yii::$app->user->isGuest,结果永远是 true。
- 正确做法:客户端在首次
send()时带上 token 或 user_id,服务端在onMessage中解析并验证,再绑定到连接实例(例如$connection->user_id = $uid) - Token 验证建议走
Yii::$app->getSecurity()->validatePassword()或 JWT 解析,别硬编码密钥 - Workerman 的
$connection对象不持久化,断线后所有属性丢失,别存大对象或 DB 连接
广播性能瓶颈不在 Yii2,而在 Workerman 的连接遍历方式
用 foreach ($worker->connections as $conn) 推送消息看着简单,但连接数过千时延迟明显。这不是 Yii2 慢,是 PHP 单进程遍历开销本身高。
- 避免在广播前查数据库——比如“查出所有在线管理员再推”,应提前维护内存映射(如
Worker::$adminConnections = []) - 不要在
onMessage里直接sleep()或调用阻塞 IO,Workerman 是异步单线程,一卡全卡 - 生产环境务必关掉
debug模式,Workerman 的Worker::$daemonize = true和Worker::$logFile要显式配置,否则日志刷爆磁盘
最易被忽略的一点:Workerman 进程不共享内存,Yii::$app 实例在每个 Worker 子进程中都是全新创建的,所以 Yii::$app->db 连接不会复用,也别想用 static 变量跨进程存状态。











