2

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

所有这些,我都在玩过 SplHeap 和 SplObjectStore 到层次结构并失败了。让我的面条搞砸的是我的正常递归方法失败(内存不足错误),而我的一个成功在于循环遍历每个节点并添加到数组的递归方法。这样做的问题是它忽略了 setMaxDepth() 方法并遍历了所有的孩子。我想过设置一个 $var++ 通过循环递增,限制节点,但我不相信这是“正确的方式”。

任何人,代码(抱歉,如果有任何孤立代码 - 请忽略它)...

<?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;
4

1 回答 1

1

ARecursiveIteratorIterator的主要目的是为您提供一个迭代器,其行为类似于平面列表上的迭代器,但平面列表实际上只是递归遍历中的一个序列。它通过在内部管理一堆 RecursiveIterators 来做到这一点,并getChildren()在必要时调用它们。RecursiveIteratorIterator 的客户端实际上只应该调用诸如等之类的普通方法Iterator......除了增值方法,如current()next()setMaxDepth()

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

正确的方式:

    $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";
    }

我不打算为您以某种特定的结构形成分层数组,但也许这个相关的问题可以进一步帮助您理解RecursiveIteratorIterator 如何在 PHP 中工作RecursiveIteratorIteratorRecursiveIterator 如何工作之间的区别?

于 2012-11-11T23:09:20.433 回答