我遍历了迭代器,知道为什么要使用它,但我不知道的是迭代器类的方法在通过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
, rewind
和valid
的方法。
除了valid之外,这些都是适用于普通数组的方法,只是作为过程函数而不是对象方法。(对于数组来说,valid
不存在,因为选择新项的函数将返回该项,所以可以说valid
被嵌入到这些函数中。)这表明,在底层,foreach
循环在数组和Iterable
对象上的工作方式或多或少相同。
在您的问题中链接的手册页上的示例中显示或至少暗示了在Iterable
对象上迭代的过程,但我可以看到它可能会令人困惑。下面是这个过程的基本解释:
一般来说,foreach
循环会将一个可迭代对象的指针重置回它的第一个位置(注意这里的小I——我指的是一个数组或一个实现Iterable
接口的对象)。换句话说,它"倒带"可迭代对象的方式与你倒带磁带的方式相同——这个概念可能会在年轻一代中丢失。可以想象,这是接口需要的rewind
方法。
一旦数组被重新缠绕,foreach
将尝试读取当前所选的元素。使用current
方法检索当前元素的数据,使用key
方法检索元素的键。这些项被放入您在foreach
循环中定义的变量中,循环运行它的迭代。
在循环迭代完成后,foreach
将尝试使用next
方法获取下一个元素。然后执行与上一段相同的步骤处理循环。
对于Iterable
对象,在使用current
和key
读取任何数据之前,foreach
循环将调用valid
方法。如果此方法返回FALSE
,或者PHP认为与其等价的值(如0或NULL
),则foreach
假定没有更多的处理并完全退出循环,程序继续正常运行。
没有魔法。foreach
将简单地检查对象是否实现了Iterator接口,然后按正确的顺序调用相应的方法。
您可以在这里找到更多详细信息:http://lxr.php.net/xref/PHP_5_4/Zend/zend_interfaces.c