通过foreach迭代对象时如何调用Iterator方法


How the Iterator methods are called upon iterating object through foreach

我遍历了迭代器,知道为什么要使用它,但我不知道的是迭代器类的方法在通过foreach迭代对象时是如何调用的。

考虑以下从php手册页

复制的示例
class myIterator implements Iterator {
    private $position = 0;
    private $array = array(
        "firstelement",
        "secondelement",
        "lastelement",
    );  
    public function __construct() {
        $this->position = 0;
    }
    function rewind() {
        var_dump(__METHOD__);
        $this->position = 0;
    }
    function current() {
        var_dump(__METHOD__);
        return $this->array[$this->position];
    }
    function key() {
        var_dump(__METHOD__);
        return $this->position;
    }
    function next() {
        var_dump(__METHOD__);
        ++$this->position;
    }
    function valid() {
        var_dump(__METHOD__);
        return isset($this->array[$this->position]);
    }
}

这里我想要理解当我像下面这样使用foreach时。

myIterator类的方法如何自动调用?

$it = new myIterator;
foreach($it as $key => $value) {
    var_dump($key, $value);
    echo "'n";
}

这里有什么神奇之处?

魔力,如果你想这样称呼它,就是当你尝试使用实现Iterator接口的对象进行迭代时,PHP有一个定义好的行为。

接口,正如你所知道的,只是程序员和应用程序之间的一个契约,它规定了某些方法将被定义。如果在定义类时没有实现接口中的方法,PHP将抛出致命错误,程序将终止。这意味着当一个foreach遇到一个实现了Iterable接口的对象时,该对象保证有称为current, key, next, rewindvalid的方法。

除了valid之外,这些都是适用于普通数组的方法,只是作为过程函数而不是对象方法。(对于数组来说,valid不存在,因为选择新项的函数将返回该项,所以可以说valid被嵌入到这些函数中。)这表明,在底层,foreach循环在数组和Iterable对象上的工作方式或多或少相同。

在您的问题中链接的手册页上的示例中显示或至少暗示了在Iterable对象上迭代的过程,但我可以看到它可能会令人困惑。下面是这个过程的基本解释:

一般来说,foreach循环会将一个可迭代对象的指针重置回它的第一个位置(注意这里的小I——我指的是一个数组或一个实现Iterable接口的对象)。换句话说,它"倒带"可迭代对象的方式与你倒带磁带的方式相同——这个概念可能会在年轻一代中丢失。可以想象,这是接口需要的rewind方法。

一旦数组被重新缠绕,foreach将尝试读取当前所选的元素。使用current方法检索当前元素的数据,使用key方法检索元素的键。这些项被放入您在foreach循环中定义的变量中,循环运行它的迭代。

在循环迭代完成后,foreach将尝试使用next方法获取下一个元素。然后执行与上一段相同的步骤处理循环。

对于Iterable对象,在使用currentkey读取任何数据之前,foreach循环将调用valid方法。如果此方法返回FALSE,或者PHP认为与其等价的值(如0或NULL),则foreach假定没有更多的处理并完全退出循环,程序继续正常运行。

没有魔法。foreach将简单地检查对象是否实现了Iterator接口,然后按正确的顺序调用相应的方法。

您可以在这里找到更多详细信息:http://lxr.php.net/xref/PHP_5_4/Zend/zend_interfaces.c