SplRecurisveDirectoryIterator&分层数组

时间:2012-10-30 20:53:01

标签: php hierarchical-data spl

我想玩一些PHP的迭代器,并设法得到一个可靠的(从我的理解)构建。我的目标是在父文件夹内迭代并获得2个节点;在此过程中构建分层树阵列。显然,我可以使用glob和几个嵌套循环相当容易地做到这一点,但我想使用Spl类来实现这一点。

所有这一切,我已经玩SplHeap和SplObjectStore到层次结构并失败了。什么弄乱我的面条是我正常的递归方法失败(内存不足错误)和我的成功落在一个循环方法循环每个节点,添加到一个数组。问题是它忽略了setMaxDepth()方法并遍历所有子节点。我考虑过设置一个$ var ++来增加循环,限制节点,但我不相信这是“正确的方法”。

Anywho,代码(对不起任何孤立的代码,如果有的话 - 只是忽略它)......

<?php
namespace Tree;

use RecursiveFilterIterator,
    RecursiveDirectoryIterator,
    RecursiveIteratorIterator;

class Filter extends RecursiveFilterIterator {
    public static $FILTERS = array(
        '.git', '.gitattributes', '.gitignore', 'index.php'
    );

    public function accept() {
        if (!$this->isDot() && !in_array($this->current()->getFilename(), self::$FILTERS))
            return TRUE;

        return FALSE;
    }
}

class DirTree {
    const MAX_DEPTH = 2;

    private static $iterator;
    private static $objectStore;

    public function __construct() {

        error_reporting(8191);
        $path       = realpath('./');

        try {

            $dirItr     = new RecursiveDirectoryIterator($path);
            $filterItr  = new Filter($dirItr);
            $objects    = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST);

            $objects->setMaxDepth(self::MAX_DEPTH);

            echo '<pre>';
            print_r($this->build_hierarchy($objects));

        } catch(Exception $e) {
            die($e->getMessage());
        }
    }

    public function build_hierarchy($iterator){
        $array = array();
        foreach ($iterator as $fileinfo) {

            if ($fileinfo->isDir()) {
                // Directories and files have labels
                $current = array(
                    'label' => $fileinfo->getFilename()
                );
                // Only directories have children
                if ($fileinfo->isDir()) {
                    $current['children'] = $this->build_hierarchy($iterator->getChildren());
                }
                // Append the current item to this level
                $array[] = $current;
            }
        }
        return $array;
    }
}

$d = new DirTree;

1 个答案:

答案 0 :(得分:1)

RecursiveIteratorIterator主要用于为您提供一个迭代器,其行为类似于平面列表上的迭代器,但平面列表实际上只是递归遍历中的一个序列。它通过内部管理Stack of RecursiveIterators来实现,在必要时调用它们getChildren()。 RecursiveIteratorIterator的客户端实际上应该调用Iteratorcurrent()之类的常规next()方法...除了setMaxDepth()

您的问题是您尝试通过调用getChildren()来自行进行递归。如果你想手动管理递归,那很好 - 但这会使RecursiveIteratorIterator多余。事实上,我很惊讶在getChildren上调用RecursiveIteratorIterator()并没有致命的错误。这是RecursiveIterator方法。 spl可能只是将方法调用转发给内部迭代器(一些spl类转发方法调用未定义的方法,以便于使用Decorator设计模式)。

正确的方式:

    $dirItr     = new RecursiveDirectoryIterator($path);
    $filterItr  = new Filter($dirItr);
    $objects    = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST);

    $objects->setMaxDepth(self::MAX_DEPTH);

    echo '<pre>';
    foreach ($objects as $splFileInfo) {
        echo $splFileInfo;
        echo "\n";
    }

我不打算在某些特定结构中为您构建分层数组,但也许这个相关问题可以进一步帮助您理解RecursiveIteratorIteratorRecursiveIterator之间的区别 How does RecursiveIteratorIterator work in PHP?