我们可以在 php 的 foreach 循环中使用 IterateAggregate 或 Iterator 吗?

Can we use IterateAggregate or Iterator in foreach loop in php?

我是 php 的初学者,正在从 php.net 学习它。该页面 (http://php.net/manual/en/class.traversable.php) 上的 注释 说:

实现此接口的内部(内置)classes 可以在 foreach 构造中使用,不需要实现 IteratorAggregate 或 Iterator。

这个注释说的是什么?这是否意味着我们可以在 foreach 循环中使用 IteratorAggregateIterator 而无需任何 class 或者我错了。谁能告诉我这个 note 说的是什么??

IteratorAggregate 是一个 接口,用于创建一个外部迭代器,它允许您遍历自定义 class 对象 使用 foreach:

class FooBarClass implements IteratorAggregate
{
    public $property = "Nothing to see";

    public function __construct()
    {
    }

    public function getIterator()
    {
        return new ArrayIterator($this);
    }
}

$obj = new FooBar;

foreach($obj as $key => $value) {
    print(var_dump($key, $value) . "\n");
}

Iterator 也是一个 外部迭代器的接口 但允许您的 class 对象或对象在内部迭代它们自己:

class myIterator implements Iterator
{
    private $position = 0;
    private $array = array('one', 'two', 'three');

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

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

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

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

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

尽管如此,您仍然可以像 IteratorAggregate 一样遍历对象。

两者的区别在于 IteratorAggregate 比迭代器更容易实现,而且通常速度更快。缺点是它只是用于遍历,并没有提供next()、key()等方法,因为这些方法在foreach遍历时不会被调用。

虽然 Iterator(或更具体的 OuterIterator or (easier) an IteratorIterator)允许您更好地控制对象的迭代并在 next()、key() 或prev() 失败、缓存() 等

你所指的注释是指PHP的某些内部classes(用C代码编写)可能直接实现了这个接口.任何需要实现 Traversable 的用户空间 class 必须通过实现 IteratorAggregate 或 Iterator 或另一个 Traversable 的后代来实现。参见 Pro PHP by Kevin McArthur 第143f.

Traversable 接口本身是一个抽象基接口(没有接口概要中显示的方法),无法实例化。但是,它可以用来检查 class 是否可以使用 foreach 遍历。

Traversable {
}

混淆部分是对象和数组实现"Traversable",但can be traversed by foreach, but you cannot check for foreach compatibility using an instanceof check or type hint

$myarray = array('one', 'two', 'three');
$myobj = (object)$myarray;

if ( !($myarray instanceof \Traversable) ) {
    print "myarray is NOT Traversable";
}
if ( !($myobj instanceof \Traversable) ) {
    print "myobj is NOT Traversable";
}

如前所述,每个对象都可以用 foreach 遍历,但是你只能访问 public 属性。引用 Object Iteration 上的 PHP 手册:

PHP 5 provides a way for objects to be defined so it is possible to iterate through a list of items, with, for example a foreach statement. By default, all visible properties will be used for the iteration.

因此,如果您使用私有值和受保护值封装对象并编写 getter 和 setter 方法来访问它,您可能希望 class 实现 IteratorAggregate 或 Iterator 并且编写逻辑,使这些值可以根据需要在 foreach 循环中访问。

简而言之,实现 Traversable 接口的对象(通过 Iterator 或 IteratorAggregate)"act like an array"。但是,没有必要迭代对象。但是如果你想改变它们的行为,你需要实现迭代器。同样的逻辑适用于内置 classes.