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

sun*_*ght 5 php iterator

我浏览了Iterator并明白了为什么应该使用它,但我没有明白的是迭代器类的方法如何在通过 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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里我想了解一下当我使用 foreach 时的情况,如下所示。

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

$it = new myIterator;

foreach($it as $key => $value) {
    var_dump($key, $value);
    echo "\n";
}
Run Code Online (Sandbox Code Playgroud)

这里有什么魔力?

Age*_*rum 2

如果您想这样称呼它,那么“神奇”就是当您尝试使用实现该Iterator接口的对象进行迭代时,PHP 具有已定义的行为。

您可能知道,接口只是程序员和应用程序之间的契约,规定将定义某些方法。如果定义类时没有实现接口中的方法,PHP 将抛出致命错误,并且程序将终止。这意味着当遇到foreach实现该接口的对象时Iterable,该对象保证具有名为currentkeynextrewind的方法valid

除了 valid 之外,这些方法也适用于普通数组,尽管是过程函数而不是对象方法。(valid数组不存在,因为选择新项目的函数将返回该项目,因此您可以说它valid已融入这些函数中。)这表明,在幕后,foreach循环的工作方式或多或少相同在数组和Iterable对象上。

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

一般来说,foreach循环会将可迭代对象的指针(注意这里的小 I - 我指的是实现接口的数组或对象Iterable)重置回其第一个位置。换句话说,它以与倒带磁带相同的方式“倒带”可迭代对象——年轻一代可能会忘记这个概念。正如您可能想象的那样,这是rewind该接口所需的方法。

一旦数组倒回,就会foreach尝试读取当前选择的任何元素。使用该方法检索当前元素的数据current,并使用该方法检索元素的键key。这些项目被放入您在循环中定义的变量中foreach,并且循环运行其迭代。

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

Iterable对象上,在使用currentand读取任何数据之前keyforeach循环将调用该valid方法。如果此方法返回FALSE或 PHP 认为与其等效的值(例如 0 或NULL),foreach则假定没有更多内容需要处理并完全退出循环,并且您的程序将照常继续。