RecursiveFilterIterator:如何不接受对象,但仍然访问他们的孩子?

时间:2013-10-15 17:10:43

标签: php recursion spl filter-iterator

我很难让RecursiveFilterIterator访问我不想接受的对象的子项,而不返回不可接受的对象。

我有两种类型的Node对象:NodeTypeANodeTypeA,它们都扩展抽象类型Node

abstract class Node implements Countable, RecursiveIterator
{
    protected $children;

    public function __construct( array $children = array() )
    {
        $this->children = $children;
    }

    public function count()
    {
        return count( $this->children );
    }

    public function hasChildren()
    {
        if( !$this->valid() )
        {
            return false;
        }

        return count( $this->current() ) > 0;
    }

    public function getChildren()
    {
        return $this->current();
    }

    public function rewind()
    {
        reset( $this->children );
    }

    public function key()
    {
        return key( $this->children );
    }

    public function valid()
    {
        return null !== $this->key();
    }

    public function current()
    {
        return current( $this->children );
    }

    public function next()
    {
        next( $this->children );
    }
}

class NodeTypeA extends Node {}

class NodeTypeB extends Node {}

...我为此定义了这个RecursiveFilterIterator

class RecursiveNodeFilterIterator
    extends RecursiveFilterIterator
{
    public function __construct( RecursiveIterator $iterator, $kind )
    {
        parent::__construct( $iterator );

        $this->kind = $kind;
    }

    public function accept()
    {
        $current = $this->current();
        return $this->hasChildren() || $current instanceof $this->kind;
    }

    public function getChildren()
    {
        return new self( $this->getInnerIterator()->getChildren(), $this->kind );
    }
}

然后,当我运行此代码段时:

header( 'Content-Type: text/plain; charset=utf-8' );

$nodes = new NodeTypeA( array(
    new NodeTypeB( array(
        new NodeTypeA( array(
            new NodeTypeB( array(
                new NodeTypeA(),
                new NodeTypeA()
            ) ),
        ) ),
        new NodeTypeA( array(
            new NodeTypeB( array(
                new NodeTypeB( array(
                    new NodeTypeA(),
                    new NodeTypeB()
                ) ),
            ) )
        ) ),
        new NodeTypeB()
    ) ),
    new NodeTypeA()
) );

$rii = new RecursiveIteratorIterator(
    new RecursiveNodeFilterIterator( $nodes, 'NodeTypeA' ),
    RecursiveIteratorIterator::SELF_FIRST
);

foreach( $rii as $node )
{
   echo str_repeat( '  ', $rii->getDepth() ) . get_class( $node ) . PHP_EOL;
}

我希望得到这个结果:

  NodeTypeA
      NodeTypeA
      NodeTypeA
  NodeTypeA
        NodeTypeA
NodeTypeA

......但得到了:

NodeTypeB
  NodeTypeA
    NodeTypeB
      NodeTypeA
      NodeTypeA
  NodeTypeA
    NodeTypeB
      NodeTypeB
        NodeTypeA
NodeTypeA

换句话说,在迭代时,它还会在有子项时返回NodeTypeB个对象。这是有道理的,因为在RecursiveNodeFilterIterator::accept()我定义了return $this->hasChildren() || ...,以便过滤器访问所有可能的子节点。

有没有办法让RecursiveNodeFilterIterator访问NodeTypeB的子节点而不实际返回NodeTypeB个节点?

1 个答案:

答案 0 :(得分:2)

一个简单的选择是使用过滤迭代器包装RecursiveIteratorIterator,只有accept个您感兴趣的项目。

(从评论移至回答)