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 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化