【问题标题】:PHP Recursive Iterator leavesPHP 递归迭代器离开
【发布时间】:2013-06-14 02:04:31
【问题描述】:

我试图更好地理解 PHP 中的迭代器。对于这个测试,我想制作一个项目树,并用不同的RecursiveIteratorIterator 模式列出它们。 ::SELF_FIRST 和 ::CHILD_FIRST 模式按我的预期工作。但是,当我想列出叶子时它不会。我在实现中一定缺少一些东西,它不允许该模式正常工作,因为它什么也没打印出来。我的Obj::hasChildren() 方法有问题吗?

这里是测试类:

class Obj implements \RecursiveIterator {
    public $children = array();

    private $position;

    private $name;

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

    public function valid()
    {
        return isset($this->children[$this->position]);
    }

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

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

    public function rewind()
    {
        $this->position = 0;
    }

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

    public function hasChildren()
    {
        return !empty($this->children[$this->position]);
    }

    public function getChildren()
    {
        return $this->children[$this->position];
    }

    public function __toString()
    {
        return $this->name;
    }
}

这是测试:

use RecursiveIteratorIterator as RII;

$o1 = new Obj('Root');

$i1 = new Obj('Item 1');
$i12 = new Obj('Subitem 2');
$i1->children[] = new Obj('Subitem 1');
$i1->children[] = $i12;

$i12->children[] = new Obj('Subsubitem 1');
$i12->children[] = new Obj('Enough....');

$o1->children[] = $i1;
$o1->children[] = new Obj('Item 2');
$o1->children[] = new Obj('Item 3');

foreach (new RII($o1, RII::LEAVES_ONLY) as $o) {
    echo "<br>" . $o;
}

【问题讨论】:

标签: php iterator spl


【解决方案1】:

您假设指向正确的方向,您的 hasChildren() 方法存在问题。将其与 valid()current() 方法进行比较,您可能已经看到它总是返回 true。

因为只要有current()hasChildren()就返回true:

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

和:

public function hasChildren()
{
    return !empty($this->children[$this->position]);
}

相反,您想测试当前元素是否有子元素:

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

将为您提供输出的细微差别:

Subitem 1
Subsubitem 1
Enough....
Item 2
Item 3

通过始终为hasChildren() 返回TRUERecursiveIteratorIterator 无法检测到任何叶子。根据树的概念,这是不可能的,但在遍历过程中-正如您用“错误”所证明的那样-显然是可能的:)

也可以看看(如果可以的话):

【讨论】:

  • 你说得对!谢谢你!以及令人惊叹的深度RII解释,这比官方文档要好得多!
  • 另外,我可能有一些奇怪的推理方式,但我没有找到正确命名的方法 hasChildren() 和 getChildren()?如果我有一个实现 RecursiveIterator 接口的类,我基本上必须将我的 getChildren() (它将所有子元素作为数组或类似的东西返回)重命名为描述性较差的东西。
  • @igorpan:对于命名:请记住,Iterator 对象不能是您的集合对象。它只是知道如何迭代您的集合的迭代器对象。因此,您不必在一个对象中执行此操作。你看出区别了吗? (如果不只是回问)
  • 我意识到这一点,但由于我的集合是一个简单的数组,因此为此目的使用对象真的有意义吗?
  • 是的,因为迭代器为您的特定数组“类型”添加了递归迭代 - 例如,它实现了您在数组中排列子节点的方式。因此它特别有意义,因为您可以将数组保留为容器结构,并且仅在迭代时创建迭代器。这样您就可以从数组的递归迭代中受益,如果它发生变化,您可以创建一个新的迭代器。其余代码无需更改。
猜你喜欢
  • 2013-12-01
  • 1970-01-01
  • 2013-11-11
  • 2014-05-13
  • 2015-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多