递归遍历时路径变量被复用会导致路径污染,正确做法是每层生成新路径副本如 $newPath = array_merge($path, [$key]);权限节点同名时应优先用唯一ID或显式字段构建路径;需前置校验可读性再判断目录类型,并捕获异常处理软链接;结果合并推荐返回值模式而非引用传参。

递归遍历时路径变量被复用导致重复父级
最常见问题是直接在原数组上 $path[] = $key,结果所有分支共享同一引用,folder2 的文件路径里混进 folder1。根源是 PHP 数组默认按值传递,但若函数参数声明为引用或在循环中反复 push/pop 同一数组,就会污染上下文。
正确做法是每层递归生成新路径副本:
-
$newPath = array_merge($path, [$key])—— 不修改原$path,确保子调用路径干净 - 把
$newPath传给下一层,而不是复用或全局变量 - 叶子节点(如权限项)记录时,直接用当前
$path,它已是完整层级快照
权限节点结构中键名不唯一,如何避免路径歧义?
当多个节点同名(比如不同模块都有 view 权限),仅靠 $key 拼路径会丢失上下文。不能只存 ['user', 'view'],得区分 ['admin', 'user', 'view'] 和 ['api', 'user', 'view']。
解决方式取决于数据源头:
立即学习“PHP免费学习笔记(深入)”;
- 若原始结构带唯一 ID(如
id: "user_view_001"),优先用 ID 构建路径,$path[] = $node['id'] - 若只有名称,且层级语义明确,用
array_merge($path, [$node['module'], $node['action']])显式带入上下文字段 - 避免依赖
basename($pathString)反推,容易在重名时出错
遇到不可读目录或软链接时递归中断怎么办?
权限节点常映射真实目录结构,is_dir() 在无权限路径上可能静默失败,或对软链接判断异常,导致整个递归提前终止。
必须前置校验并捕获异常:
- 先
is_readable($fullPath),再is_dir($fullPath)—— 顺序不能反,否则不可读目录调is_dir()可能返回false而不报错 - 用
try/catch包裹scandir()或RecursiveDirectoryIterator初始化,捕获UnexpectedValueException - 对软链接,默认不跟随;如需展开,构造
RecursiveDirectoryIterator时加RecursiveDirectoryIterator::FOLLOW_SYMLINKS标志
递归结果要合并多层路径,array_merge() 还是引用传参?
收集最终权限路径列表时,别用引用传参(&$list)累积结果 —— 容易因递归深度大、分支多导致状态混乱,调试困难。
推荐统一返回值模式:
- 每个递归调用返回本层及所有子层的路径数组,如
return array_merge($currentPaths, $subPaths) - 顶层调用直接接收完整结果,不依赖外部变量
- 若性能敏感(超深嵌套),可改用引用传参,但必须配合
array_push($list, ...$paths)展开追加,避免$list = array_merge($list, $paths)频繁复制大数组
路径本身是轻量结构,真正容易出错的是拼接逻辑和异常边界——只要路径副本独立、校验前置、结果归并清晰,权限树就能稳定展开。



















