2

私は PHP のイテレータのいくつかを試してみたいと思っていましたが、(私の理解では) 確実なビルドを行うことができました。私の目標は、親フォルダー内で反復処理を行い、2 つのノードをダウンさせることでした。プロセス中に階層ツリー配列を構築します。明らかに、グロブといくつかの入れ子になったループを使用してこれをかなり簡単に行うことができますが、これを達成するために Spl クラスを使用したいと考えています。

邪魔にならないように、私は SplHeap と SplObjectStore を階層化して遊んで失敗しました。私の麺を台無しにしているのは、再帰の通常の方法が失敗しており(メモリ不足エラー)、私の1つの成功は、各ノードをループして配列に追加する再帰的方法です。問題は、 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は主に、フラット リストに対するイテレータのように動作するイテレータを提供するように設計されていますが、フラット リストは実際には再帰トラバーサルの単なるシーケンスです。これは、RecursiveIterator の Stack を内部で管理し、getChildren()必要に応じて呼び出すことによって行われます。RecursiveIteratorIterator のクライアントは、実際には などの通常のメソッドのみを呼び出すことになっています...Iteratorのような付加価値のあるメソッドは例外ですcurrent()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";
    }

特定の構造で階層配列を形成することには触れませんが、この関連する質問は、 PHP で RecursiveIteratorIterator がどのように機能するかRecursiveIteratorIteratorの違いを理解するのにさらに役立つかもしれません。RecursiveIterator

于 2012-11-11T23:09:20.433 に答える