该错误是因preg_match()第二个参数非字符串(如null、array)导致php报错,workerman中因异步特性易在http/ws解析、路由匹配等场景触发,需用is_string()校验或强制类型转换。

preg_match() expects parameter 2 to be string 是什么问题
这个错误不是 Workerman 自身抛出的,而是 PHP 的 preg_match() 函数在调用时,第二个参数(即待匹配的字符串)传入了非字符串类型(比如 null、array、int 或对象),PHP 直接报错中断执行。Workerman 作为常驻进程框架,一旦某次请求/回调中触发该错误且未捕获,就会导致当前 Worker 进程退出或连接异常。
常见触发位置包括:HTTP 请求体解析、WebSocket 消息处理、自定义路由匹配、中间件里对 $_GET / $_POST / $request->get() 等值直接丢给 preg_match() 做校验,而没做类型判断。
为什么在 Workerman 里特别容易踩这个坑
Workerman 的异步非阻塞特性会让变量生命周期和调试路径变得隐蔽,尤其以下场景高发:
-
$request->post()或$request->get()返回的是array,但有人误以为某个键一定存在且是字符串,直接写成preg_match('/^\d+$/', $request->get('id')) - WebSocket 收到的
$frame->data可能是binary(二进制数据)、null(如 ping/pong 帧),但代码默认当作 UTF-8 字符串处理 - 使用
json_decode()解析客户端数据后未检查返回值,当 JSON 格式错误时返回null,后续仍传给preg_match() - 路由正则匹配前,对 URI path 做了
urldecode()或其他转换,结果得到false(例如urldecode('%'))
怎么快速定位和修复
先确认出错行号(看完整错误堆栈,重点找你自己的文件),然后围绕 preg_match() 调用点做三件事:
- 检查第二个参数是否可能为非字符串:用
is_string()或!empty()+is_scalar()做兜底 - 所有来自网络输入的变量,一律先强制转字符串(谨慎!仅限明确需要字符串匹配的场景):
(string)$value,但要注意null→''、array→'Array'可能引入逻辑 bug - 更安全的做法是提前过滤或拒绝异常输入:
// ❌ 危险写法
preg_match('/^\w+$/i', $request->get('username'));
<p>// ✅ 推荐写法
$username = $request->get('username');
if (!is_string($username) || $username === '') {
// 返回错误响应或跳过匹配
return;
}
preg_match('/^\w+$/i', $username);
</p>
- 如果是在 WebSocket 中处理
$frame->data,务必先判断帧类型和数据类型:if ($frame->opcode === \Workerman\Protocols\Websocket::BINARY) { // 不适合 preg_match,考虑 unpack 或跳过 return; } $data = $frame->data; if (!is_string($data)) { return; }
Workerman 环境下还要注意的兼容细节
- Workerman 默认不开启
display_errors,错误可能只写日志不报给前端,务必检查 Worker::$logFile 或系统日志
- 在
onMessage、onRequest 等回调里未用 try...catch 包裹业务逻辑时,这类 PHP Warning 会直接终止当前请求处理,但 Worker 进程本身不会崩——这点容易让人误判问题范围
- PHP 8.0+ 对
preg_match() 的类型检查更严格,PHP 7.x 可能静默转字符串,升级后突然报错是常见现象
display_errors,错误可能只写日志不报给前端,务必检查 Worker::$logFile 或系统日志onMessage、onRequest 等回调里未用 try...catch 包裹业务逻辑时,这类 PHP Warning 会直接终止当前请求处理,但 Worker 进程本身不会崩——这点容易让人误判问题范围preg_match() 的类型检查更严格,PHP 7.x 可能静默转字符串,升级后突然报错是常见现象类型校验这一步,在 Webman、GatewayWorker 或纯 Worker 场景里都不能省;看似多写两行 is_string(),实际省去半天查日志和复现的时间。











