Webman是基于Workerman的高性能PHP框架,采用常驻内存与异步非阻塞架构,需手动启用WebSocket路由、维护Redis在线状态、显式调用$connection->send()实现消息广播。

Webman 是一个基于 Workerman 的高性能 PHP HTTP/WebSocket 框架,轻量、无依赖、启动快,特别适合做实时通讯类应用。它不像 Swoole 那样需要编译扩展,也不像 Ratchet 那样重度依赖事件循环抽象——Webman 直接封装了 Workerman 的底层能力,把 WebSocket 服务当作“路由”来管理,开发体验接近 ThinkPHP/Laravel。
但正因为这种简洁,很多开发者在用 Webman 搭建聊天室时会卡在几个关键点上:连接没触发、消息不广播、用户状态丢失、上线人数不准。这些问题不是框架不行,而是对它的运行模型理解不到位。
Webman 的 WebSocket 路由必须显式启用
Webman 默认只启动 HTTP 服务。WebSocket 不是自动开启的附加功能,必须手动注册路由并启用对应监听。
- 在
config/route.php中添加:use Webman\Route; Route::websocket('/chat', app\controller\ChatController::class); - 确保
config/server.php中启用了 WebSocket 协议监听:'websocket' => [ 'handler' => \Webman\WebSocket\Server::class, 'listen' => 'ws://0.0.0.0:8787', ], - 启动命令不是
php webman start,而是带--d守护模式并确认输出里有WebSocket server started字样 - 常见错误:只改了路由没开
websocket配置项,或端口被防火墙/Nginx 拦截(Nginx 必须透传Upgrade和Connection头)
onOpen/onMessage 不在控制器方法里直接写
Webman 的 WebSocket 控制器(如 ChatController)不是传统 MVC 的“动作方法”,它本质是事件处理器的代理类。真正起作用的是以下三个魔术方法:
立即学习“PHP免费学习笔记(深入)”;
-
onConnect:等价于onOpen,连接建立时调用,参数是$connection对象 -
onMessage:收到客户端消息时触发,第二个参数是原始字符串(不是自动 JSON 解析) -
onClose:连接关闭时触发,用于清理用户状态
容易踩的坑:
- 在
onMessage里直接echo $msg或return—— 这不会发回客户端,必须显式调用$connection->send() - 把用户 ID 存在
$connection->uid后没做全局映射,导致onClose时无法从在线列表中移除 - 忘记给
$connection设置唯一标识(比如从 URL query 或 token 中解析),结果所有匿名连接都算作“同一人”
示例片段(简化):
public function onMessage($connection, $data)
{
$msg = json_decode($data, true);
if (!$msg || !isset($msg['type'])) return;
<pre class="brush:php;toolbar:false;">// 广播给其他人(排除自己)
foreach ($this->connections as $conn) {
if ($conn !== $connection && $conn->uid) {
$conn->send(json_encode(['from' => $connection->uid, 'content' => $msg['content']]));
}
}}
在线用户列表必须自己维护,Webman 不提供内置 session
Webman 的 $connection 是短期存活对象,不绑定 PHP session,也不跨进程共享。这意味着:
- 不能靠
$_SESSION存用户信息 - 不能用
static $users = []—— 多 worker 进程下数据不同步 - 必须借助外部存储:Redis 是最常用选择(用
incr/decr+hSet/hGetAll组合管理)
典型做法:
-
onConnect时生成唯一uid(如 JWT 解析或数据库查出),存入 Redis Hash:HSET online_users $uid "$json_info" - 同时用
INCR chat:online_count计数 -
onClose时HDEL online_users $uid+DECR chat:online_count - 前端轮询 / 或通过另一个 WebSocket topic 推送在线数变更
忽略这点会导致:页面显示“12人在线”,实际只有3个真实连接;或者用户刷新后身份丢失,被当成新访客重复加入。
Webman 的优势在于简单和可控,但它不会替你做状态协调。真正难的不是连上 WebSocket,而是让每个连接知道“谁在说话”“谁已离开”“消息该往哪推”。这些逻辑必须自己补全,且优先考虑多进程下的数据一致性——否则上线一测,就发现用户列表错乱、消息漏发、计数飘忽。



















