一个自定义PHP函数,用于递归迭代目录并输出分层的多维数组?

时间:2016-09-08 11:20:52

标签: php arrays recursion multidimensional-array iterator

一个自定义PHP函数,用于递归迭代目录并输出分层的多维数组?

使用新的SPL Iterator类(RecursiveIterator *),我一直在研究以下函数:

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文件和一个右侧栏子目录。)

2 个答案:

答案 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)

使用RecursiveDirectoryIteratorRecursiveIteratorIterator和一些参考杂耍,您可以通过一个显式循环来完成此操作。

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可以避免使用显式嵌套循环。当你发现自己在这里使用显式嵌套循环时,你要么没有正确使用迭代器,要么迭代器本身不适合任务(可能这是递归函数的域)。当然,总有边缘情况,但是,对于大多数情况,这个规则都有。