dpfl37651 2013-07-31 22:18
浏览 66
已采纳

RecursiveIteratorIterator和嵌套的RecursiveArrayIterators

I've been messing with RecursiveArrayIterators for handling nested objects as trees. The following code is bothering me as the result is returning only some of the values I'm expecting. Mainly, the root node seems to never be iterated over. I have a feeling I've just been staring at it a bit too long but wanted to make sure I was on the right track with this.

class Container extends \RecursiveArrayIterator
{
    protected $_alias;

    public function __construct( $alias = null )
    {
        if( is_null( $alias ) )
        {
            $alias = uniqid( 'block_' );
        }

        $this->_alias = $alias;
    }

    public function getAlias()
    {
        return $this->_alias;
    }
}

try
{
    $root = new Container( 'root_level' );
    $block = new Container( 'first_level' );
    $child = new Container( 'second_level' );
    $child_of_child_a = new Container( 'third_level_a' );
    $child_of_child_b = new Container( 'third_level_b' );

    $child->append( $child_of_child_a );
    $child->append( $child_of_child_b );
    $child_of_child_a->append( new Container );
    $child_of_child_a->append( new Container );
    $block->append( $child );
    $root->append( $block );

    $storage = new \RecursiveIteratorIterator( $root, RecursiveIteratorIterator::SELF_FIRST );

    foreach( $storage as $key => $value )
    {
        print_r( str_repeat( ' ', $storage->getDepth() * 4 ) . $value->getAlias() . PHP_EOL );
    }
}
catch( \Exception $e )
{
    var_dump( $e->getMessage() );
}

With the result being...

first_level
second_level
    third_level_a
        block_51f98b779c107
        block_51f98b779c124
    third_level_b

Where's the root node?

ANSWER

Sven's answer jarred my over-worked brain into processing this correctly. This was my final bit of successful code in case someone else is attempting something similar.

class OuterContainer extends \ArrayIterator
{

}

class Container extends \ArrayIterator
{
    protected $_alias;

    public function __construct( $alias = null )
    {
        if( is_null( $alias ) )
        {
            $alias = uniqid( 'container_' );
        }

        $this->_alias = $alias;
    }

    public function getAlias()
    {
        return $this->_alias;
    }
}

try
{
    $c1 = new Container( 'Base' );

    $c1_c1 = new Container( 'Base > 1st Child' );

    $c1_c2 = new Container( 'Base > 2nd Child' );

    $c1_c1_c1 = new Container( 'Base > 1st Child > 1st Child' );

    $c1_c1->append( $c1_c1_c1 );

    $c1->append( $c1_c1 );

    $c1->append( $c1_c2 );

    $outer_container = new OuterContainer;

    $outer_container->append( $c1 );

    $storage = new \RecursiveIteratorIterator( new \RecursiveArrayIterator( $outer_container ), RecursiveIteratorIterator::SELF_FIRST );

    foreach( $storage as $key => $value )
    {
        print_r( $value->getAlias() . PHP_EOL );
    }
}
catch( \Exception $e )
{
    var_dump( $e->getMessage() );
}
  • 写回答

1条回答 默认 最新

  • dongrenshi0889 2013-07-31 22:35
    关注

    The root node is not there because you are not using the RecursiveArrayIterator correctly.

    It's intended use is to have an array with multiple sub-arrays in any level and structure, and give this array into ONE instance of the RecursiveArrayIterator, and to iterate over everything, put this into a RecursiveIteratorIterator.

    That way, the entire array, including it's top level, will be iterated.

    Because you abused the RecursiveArrayIterator to be the carrier of information, the top level object is not iterated.

    Suggested easy example that has some nastyness, but demonstrates the principle:

    $root = array( 'root_level' );
    $block = array( 'first_level' );
    $child = array( 'second_level' );
    $child_of_child_a = array( 'third_level_a' );
    $child_of_child_b = array( 'third_level_b' );
    
    $child[] = $child_of_child_a;
    $child[] = $child_of_child_b ;
    $child_of_child_a[] = array('');
    $child_of_child_a[] = array('');
    $block[] = $child;
    $root[] = $block ;
    
    $storage = new \RecursiveIteratorIterator( new \RecursiveArrayIterator($root), RecursiveIteratorIterator::SELF_FIRST );
    
    var_dump($root);
    foreach ($storage as $key=>$value) {
        echo $key.": ".$value."
    ";
    }
    

    Result output:

    array(2) {
        [0] =>
      string(10) "root_level"
      [1] =>
      array(2) {
            [0] =>
        string(11) "first_level"
        [1] =>
        array(3) {
                [0] =>
          string(12) "second_level"
          [1] =>
          array(1) {
                    ...
                }
          [2] =>
          array(1) {
                    ...
                }
        }
      }
    }
    0: root_level
    1: Array
        0: first_level
    1: Array
        0: second_level
    1: Array
        0: third_level_a
    2: Array
        0: third_level_b
    

    It's output is not quite the same, but my point is that you can iterate over the structure without having every single node to be an instance of the RecursiveArrayIterator. You can add anything that is either an array, or an object acting as an array, or an object that can usefully be iterated.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?