2012-10-30 55 views
2

我想玩一些PHP的迭代器,并设法得到一个坚实的(从我的理解)建设去。我的目标是在父文件夹内迭代并获取2个节点;在这个过程中建立一个分层的树型数组。很明显,我可以使用glob和一些嵌套循环来很容易地完成这个任务,但是我想使用Spl类来完成这个任务。SplRecurisveDirectoryIterator&分层数组

所有这一切,我已经玩过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

一个RecursiveIteratorIterator设计主要是为了给你在一个平面列表的行为就像一个迭代的迭代器,但是扁平列表实际上只是递归遍历中的一个序列。它通过内部管理一个RecursiveIterators堆栈来完成,根据需要调用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"; 
    } 

我不打算进入形成一些特定结构的分级阵列中的你,但也许此相关的问题进一步帮助您了解RecursiveIteratorIteratorRecursiveIterator 之间的区别How does RecursiveIteratorIterator work in PHP?