一个自定义PHP函数,用于递归迭代目录并输出分层的多维数组?
function directoryToArray( $directory ) {
$array = [];
$objects = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $directory ), RecursiveIteratorIterator::SELF_FIRST );
foreach ( $objects as $name => $object ) {
if ( !( $object->getFilename() == "." | $object->getFilename() == ".." ) ) {
$path = $object->isDir() ? [
[
'name' => $object->getFilename(),
'file' => $object->getFilename(),
'children' => []
]
] : [
[
'name' => friendlyName( $object->getFilename() ),
'file' => $object->getFilename(),
]
];
for ( $depth = $objects->getDepth() - 1; $depth >= 0; $depth-- ) {
$path = [
$objects->getSubIterator( $depth )->current()->getFilename() => $path,
];
}
$array = array_merge_recursive( $array, $path );
}
}
return $array;
}
目前产生以下输出:
Array
(
[0] => Array
(
[name] => Anchor Links
[file] => anchor-links.php
)
[1] => Array
(
[name] => Columns
[file] => columns.php
)
[2] => Array
(
[name] => Page Layouts
[file] => page-layouts
[children] => Array
(
)
)
[page-layouts] => Array
(
[0] => Array
(
[name] => Right Sidebar
[file] => right-sidebar.php
)
[1] => Array
(
[name] => Left Sidebar
[file] => left-sidebar.php
)
[2] => Array
(
[name] => Right Sidebar
[file] => right-sidebar
[children] => Array
(
)
)
[right-sidebar] => Array
(
[0] => Array
(
[name] => Other Options
[file] => other-options.php
)
[1] => Array
(
[name] => Option A
[file] => option-a.php
)
[2] => Array
(
[name] => Other Options
[file] => other-options
[children] => Array
(
)
)
[other-options] => Array
(
[0] => Array
(
[name] => Sample
[file] => sample.php
)
)
)
[3] => Array
(
[name] => Changelog
[file] => changelog.php
)
)
)
但是,我想要实现的输出如下:
Array
(
[0] => Array
(
[name] => Anchor Links
[file] => anchor-links.php
)
[1] => Array
(
[name] => Columns
[file] => columns.php
)
[2] => Array
(
[name] => Page Layouts
[file] => page-layouts
[children] => Array
(
[0] => Array
(
[name] => Right Sidebar
[file] => right-sidebar.php
)
[1] => Array
(
[name] => Left Sidebar
[file] => left-sidebar.php
)
[2] => Array
(
[name] => Right Sidebar
[file] => right-sidebar
[children] => Array
(
[0] => Array
(
[name] => Other Options
[file] => other-options.php
)
[1] => Array
(
[name] => Option A
[file] => option-a.php
)
[2] => Array
(
[name] => Other Options
[file] => other-options
[children] => Array
(
[0] => Array
(
[name] => Sample
[file] => sample.php
)
)
)
)
)
[3] => Array
(
[name] => Changelog
[file] => changelog.php
)
)
)
)
我认为我们几乎就在那里,我只是想知道如何让子目录输出到[children]中的(现在)空数组。另外,不要对重复或类似的名称感到困惑(例如,在同一目录中有一个right-sidebar.php文件和一个右侧栏子目录。)
答案 0 :(得分:0)
如果您的目标是递归扫描给定目录(包括其子目录)并返回包含所有文件夹和放大器的多维数组。分层方式的文件,下面的函数: deepScan()可以帮助你。
此函数只接受一个参数:$directory
,它是要扫描的目录的路径。其他2个参数仅用于在递归过程中跟踪事物,因此应该保持不变。
该函数返回一个多维数组,其名称为目录&子目录作为键。每个子目录中的所有文件都列为该子目录的子项。
<?php
/**
* THIS FUNCTION SCANS A DIRECTORY "RECURSIVELY",
* BUILDING AN ARRAY TREE OF ALL FILES AND FOLDERS AS IT GOES...
* THIS IMPLIES THAT EVEN SUB-DIRECTORIES WILL BE SCANNED AS WELL
*
* FULL-PATH TO THE DIRECTORY TO SCAN
* @param $directory
*
* USED INTERNALLY DURING THE RECURSIVE TRIPS. LEAVE AS IS
* @param $k
*
* USED INTERNALLY DURING THE RECURSIVE TRIPS. LEAVE AS IS
* @param $key
*
* RETURNS THE RESULTING ARRAY
* @return array
*/
function deepScan($directory, &$k=null, $key=null) {
$iterator = new \DirectoryIterator ($directory);
$firstDir = basename($directory);
$dirs = [];
$dirs[$firstDir] = [];
if(!$key){ $key = $firstDir; }
if(!$k){ $k = &$dirs[$key]; }
if($k && $key){
$k[$key] = [];
$k = &$k[$key];
}
foreach($iterator as $info) {
$fileDirName = $info->getFilename();
if($info->isFile () && !preg_match("#^\..*?#", $fileDirName)){
$k[] = $directory . DIRECTORY_SEPARATOR . $fileDirName;
}else if($info->isDir() && !$info->isDot()){
$pathName = $directory . DIRECTORY_SEPARATOR . $fileDirName;
$k[$fileDirName] = $pathName;
$key = $fileDirName;
$it = &$k;
deepScan($pathName, $it, $key);
}
}
$dirs = removeEmptyEntries($dirs);
return $dirs;
}
/**
* THIS FUNCTION REMOVES/FILTERS EMPTY ENTRIES
* FROM THE RESULTING ARRAY TREE.
*
* THE ARRAY TO BE FILTERED
* @param $data
*
* RETURNS THE RESULTING FILTERED ARRAY
* @return array
*/
function removeEmptyEntries(array &$data){
foreach($data as $key=>&$item){
if(is_array($item)){
if(empty($item)) {
unset($data[$key]);
}else{
removeEmptyEntries($item);
}
}
}
foreach($data as $key=>&$item){
if(is_array($item) && empty($item)) {
unset($data[$key]);
}
}
return $data;
}
// USAGE:
$dirTree = deepScan( "/path_2_specific_directory" );
echo "<pre>";
print_r($dirTree);
echo "</pre>";
希望这可以满足您的需求。 但是,如果你想要如此特殊的输出,你可能会进一步调整它。
干杯和好运; - )
答案 1 :(得分:0)
使用RecursiveDirectoryIterator
,RecursiveIteratorIterator
和一些参考杂耍,您可以通过一个显式循环来完成此操作。
function directoryToArray($directory)
{
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$directory,
RecursiveDirectoryIterator::SKIP_DOTS
),
RecursiveIteratorIterator::SELF_FIRST
);
$files = [];
$references = [&$files];
foreach ($iterator as $item) {
$file = [
'name' => $item->getFilename(),
'file' => $item->getFilename(),
];
if ($item->isDir()) {
$file['children'] = [];
$references[$iterator->getDepth() + 1] =& $file['children'];
}
$references[$iterator->getDepth()][] = $file;
}
unset($references);
return $files;
}
请注意,此标记RecursiveDirectoryIterator::SKIP_DOTS
会过滤掉.
和..
个文件。
重要的一点。使用RecursiveIteratorIterator
可以避免使用显式嵌套循环。当你发现自己在这里使用显式嵌套循环时,你要么没有正确使用迭代器,要么迭代器本身不适合任务(可能这是递归函数的域)。当然,总有边缘情况,但是,对于大多数情况,这个规则都有。