onMessage回调必须是callable,否则Worker启动报错;支持匿名函数、函数名字符串、[object,'method']、[Class::class,'method']四种写法,各有限制和常见错误。

onMessage 回调必须是可调用的(callable),否则 Worker 启动时会报 Fatal error: Uncaught Error: Call to a member function send() on null 或直接静默失败——这是最常踩的坑。
匿名函数写法:适合快速验证和简单逻辑
最直观、最常用,尤其在调试或原型阶段。它天然绑定当前作用域,能直接访问外部变量(比如 $logger、$config),但要注意闭包变量生命周期。
常见错误现象:
– 忘记 use 引入外部变量,导致 Undefined variable
– 在回调里用了未声明的全局函数(如 dd()),而 autoloader 未加载对应类
- 务必显式
use所需变量,尤其是对象实例(如use ($db)) - 避免在匿名函数中做耗时操作(如同步 Redis 查询),会阻塞整个进程
- 示例:
$worker->onMessage = function($connection, $data) use ($logger) { $logger->info('received', ['data' => $data]); $connection->send('ok'); };
普通函数名字符串:适合复用已有函数,但易漏定义
把函数名当字符串赋给 onMessage,PHP 会在运行时动态查找该函数。好处是解耦,坏处是 IDE 难提示、启动时报错晚(函数不存在时 Worker 直接 crash)。
常见错误现象:
– 函数名拼错(如 on_mesage),报 Call to undefined function
– 函数定义在 require 之后,导致找不到
- 函数必须在
Worker::runAll()之前已声明(建议放在require_once后、new Worker前) - 函数签名必须严格为
function($connection, $data),多一个参数或少一个都会报Too few arguments - 不能用
static或private方法,只能是全局作用域下的function
数组形式的 [object, 'method']:适合封装业务逻辑到类中
这是生产环境最推荐的方式——状态可管理、测试友好、支持依赖注入。但要注意对象生命周期:Worker 进程常驻,对象不能依赖请求上下文。
常见错误现象:
– 用 new MyClass() 创建后立刻赋值,但没保存引用,PHP GC 可能回收对象
– 方法里用了 $this->request 这类只在 HTTP 请求中有效的属性(Workerman 的 onMessage 不提供 Request 对象)
- 对象必须在 Worker 实例化前创建,并保持强引用(如赋给变量)
- 方法必须是
public,且签名与回调一致:public function onMessage($connection, $data) - 避免在方法内 new 大量对象或打开文件句柄,容易内存泄漏
静态方法回调:[Class::class, 'method'] 或 'Class::method'
无需维护对象实例,适合无状态工具类(如日志格式化、协议解析)。但无法访问实例属性,也不能用 $this。
常见错误现象:
– 写成 ['MyClass', 'onMessage'](少了 ::class 或字符串全名),报 Class 'MyClass' not found
– 静态方法里误调用 $this->xxx,直接 fatal error
- 推荐写法:
$worker->onMessage = [MyClass::class, 'parseAndReply'] - 注意命名空间:如果
MyClass在App\Server下,必须写完整类名或 use 后用MyClass::class - 静态方法内所有依赖都得通过参数传入或从容器获取,不能隐式依赖
$connection 是进程内唯一、不可跨进程传递的对象,任何试图把它存进 Redis、序列化、或传给子进程的操作都会失败。这点很容易被忽略,直到线上出现连接假死或 send 不生效。










