webman实现无限级分类必须一次查全表+内存递归构建树,禁用递归中查库;需用引用挂载子节点、加深度限制防死循环、path字段前后补逗号防歧义、json输出前清理非标量值并隔离协程变量。

Webman 里做无限级分类,别直接在 buildTree 里查数据库——一次全量拉取 + 内存递归是唯一稳的路。Webman 虽轻量,但没绕过 PHP 的 memory_limit 和 xdebug.max_nesting_level,10 层以上还边查边递归,500 错误或超时是常态。
Webman 中 buildTree 必须预加载全量数据
Webman 是常驻内存模型,但 buildTree 如果每层都走一次 $this->db->select(),不仅连接池压不住,还会因重复 SQL 导致慢查询堆积。真实场景下,分类表哪怕只有 2000 行,递归 8 层就可能触发 1600 次查询。
- 必须先执行
SELECT * FROM category ORDER BY parent_id, sort,一次性拿到全部数据到 PHP 数组 - 用
array_column($list, null, 'id')构建 ID 映射表,避免每次递归都foreach全数组 - 根节点判定别写死
$parentId === 0,改用empty($item['parent_id']),兼容null、''、0三种空值 - 加深度保护:函数开头加
if ($depth > 30) { return []; },Webman 不重启进程,深递归卡住整个 worker
path 字段 LIKE 查询要防逗号歧义
Webman 做后台管理时常用 path 字段加速子树查询,但 WHERE path LIKE '0,1,%' 会误中 "0,10,105" 这类 ID。这不是 Webman 特有,是所有用字符串路径的通病。
-
path存储必须前后补逗号,例如",0,1,5,",不是"0,1,5" - 查某节点所有后代,用
WHERE path LIKE '%,1,%',不是前缀匹配 - 新增节点时,先
SELECT path FROM category WHERE id = :pid,再拼接:$newPath = $parentPath . $id . ',' -
path字段类型至少设为VARCHAR(512);ID 平均长度按 4 字节算,30 层就超 255
array_reduce 构建树必须用引用且预占位
有人想在 Webman 的 controller 里用 array_reduce 一行转树,结果返回空或 children 键错乱——根本原因是没维护好引用链,PHP 在 reduce 过程中复制了数组副本。
- 必须初始化
$ref = [],并用$ref[$item['id']] = &$item绑定引用 - 必须先遍历一遍,确保所有
$ref[$item['parent_id']]都存在(哪怕只是空数组),否则挂载失败 - 关键写法:
$ref[$item['parent_id']]['children'][] = &$ref[$item['id']],漏掉&就白干 - 别依赖原始数组顺序:
parent_id可能大于当前id,所以不能跳过未定义的$ref[$pid]
JSON 输出前必须清理非标量值
Webman 返回 JSON 时调 json_encode($tree) 报 Nesting level too deep,通常不是层级真深,而是 $tree 里混进了 PDO 对象、Resource、Closure 或循环引用数组。
- 用
json_last_error()+json_last_error_msg()确认错误类型,别瞎调max_depth - 输出前做清洗:
array_walk_recursive($tree, function(&$v) { if (!is_scalar($v)) $v = null; }); - 中文不乱码的关键是确保源数据已是 UTF-8,
json_encode()不需要额外 flag;JSON_UNESCAPED_UNICODE只用于防止 \uXXXX 转义 - Webman 的
response()->json()默认不带 header,如需Content-Type: application/json; charset=utf-8,得手动 setHeader
最易被忽略的是:Webman 的协程上下文不会自动隔离全局变量,如果在 buildTree 里用了静态缓存或全局 $ref 数组,多个并发请求会互相污染。要么用局部变量,要么加 request_id 做键名隔离。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











