PHP中如何遍历动态深度数组?优化目录路径生成代码
问题描述
需要实现文件引入时获取指定目录的绝对路径,目前已有一个基于已知文件结构遍历数组的函数,但代码嵌套多层十分冗余。尝试过DirectoryIterator及IteratorIterator,但无法实现所需的控制逻辑。部分目录(如图像目录)存在动态子文件夹,无需硬编码,想知道是否有更简洁的PHP内置函数实现方式,替代当前的冗余代码。
原代码如下:
protected function getRoot() { $directories = [ 'css' => '', 'demo' =>['clientImages',['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'includes' => ['class','inc','js'], 'login' => ['logImages',['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'public' => [['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'recover' => [['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'registration' => [['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'siteImages' => '', 'tracker' => ['clientImages',['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]] ]; foreach($directories as $path => $dirs){ $this->root[$path] = $this->getSiteRoot().$path.'/'; if(is_array($dirs)){ foreach($dirs as $dir => $sub){ if(is_array($sub)){ foreach($sub as $s => $d){ $this->root[$path.'-'.$s] = $this->root[$path].$s.'/'; if(is_array($d)){ foreach($d as $b => $a){ $this->root[$path.'-'.$b] = $this->root[$path.'-'.$s].$b.'/'; if(is_array($a)){ foreach($a as $z){ $this->root[$path.'-'.$z] = $this->root[$path.'-'.$b].$z.'/'; } } } } else { $this->root[$path.'-'.$s] = $this->root[$path.'-'.$s].$d.'/'; } } } else { $this->root[$path.'-'.$sub] = $this->root[$path].$sub.'/'; } } } } return $this->root; }
解决方案
1. 用递归函数替代多层嵌套循环
原代码的核心问题是用多层foreach处理嵌套数组,递归函数可以大幅简化逻辑,同时保留对目录结构的精确控制:
protected function getRoot() { $directories = [ 'css' => '', 'demo' =>['clientImages',['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'includes' => ['class','inc','js'], 'login' => ['logImages',['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'public' => [['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'recover' => [['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'registration' => [['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]], 'siteImages' => '', 'tracker' => ['clientImages',['config' => ['includes' => ['class','js']]],['src' => ['libs' => '']]] ]; $this->root = []; $siteRoot = $this->getSiteRoot(); // 递归处理目录结构的闭包函数 $processDirs = function($currentPath, $dirStructure, $parentKey) use (&$processDirs, $siteRoot, &$root) { foreach ($dirStructure as $key => $value) { if (is_numeric($key)) { // 处理索引数组项(如['clientImages']) $dirName = $value; $newKey = $parentKey . '-' . $dirName; $newPath = $currentPath . $dirName . '/'; $root[$newKey] = $newPath; // 自动获取动态目录的子文件夹 if (in_array($dirName, ['clientImages', 'logImages', 'siteImages'])) { $dynamicSubdirs = glob($newPath . '*', GLOB_ONLYDIR); foreach ($dynamicSubdirs as $subdir) { $subdirName = basename($subdir); $root[$newKey . '-' . $subdirName] = $subdir . '/'; } } } else { // 处理关联数组项(如['config' => [...]]) $newKey = $parentKey . '-' . $key; $newPath = $currentPath . $key . '/'; $root[$newKey] = $newPath; // 存在子结构则递归处理 if (is_array($value)) { $processDirs($newPath, $value, $newKey); } } } }; // 遍历顶层目录 foreach ($directories as $topDir => $subStructure) { $topPath = $siteRoot . $topDir . '/'; $this->root[$topDir] = $topPath; if (!empty($subStructure)) { $processDirs($topPath, $subStructure, $topDir); } } return $this->root; }
2. 动态目录处理
对于clientImages这类存在动态子文件夹的目录,用glob($path . '*', GLOB_ONLYDIR)可以自动获取所有子目录,无需硬编码。如果需要更复杂的目录遍历规则,也可以结合RecursiveDirectoryIterator和RecursiveIteratorIterator,但glob()在这个场景下更轻量直接。
3. 关于DirectoryIterator的使用说明
DirectoryIterator适合遍历真实存在的物理目录,但你的场景需要结合预设的目录结构规则(部分目录是硬编码的逻辑)和动态目录,递归处理预设数组+glob()动态获取的组合,比单纯用目录迭代器更贴合需求,能保留对目录键名的自定义控制(比如demo-config这类命名规则)。
内容的提问来源于stack exchange,提问作者Cavalier
相关产品推荐
相关产品推荐

