【问题标题】:Can we use IterateAggregate or Iterator in foreach loop in php?我们可以在 php 的 foreach 循环中使用 IterateAggregate 或 Iterator 吗?
【发布时间】:2018-03-10 21:15:49
【问题描述】:

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

实现此接口的内部(内置)类可用于 foreach 构造,无需实现 IteratorAggregate 或 Iterator。

这个注释说明了什么?这是否意味着我们可以在没有任何类的情况下在 foreach 循环中使用 IteratorAggregateIterator 或者可能是我错了。谁能说出这个note说什么??

【问题讨论】:

    标签: php foreach traversable


    【解决方案1】:

    IteratorAggregate 是一个接口,用于创建一个外部迭代器,它允许您使用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 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 或更简单的IteratorIterator)允许您更好地控制对象的迭代并在next() 上添加自定义异常,但key( ) 或 prev() 失败,caching() 等。

    您所指的注释是指PHP的一些内部类(用C代码编写)可以直接实现这个接口。任何需要实现 Traversable 的用户态类都必须通过实现 IteratorAggregate 或 Iterator 或其他 Traversable 的后代来实现。见Pro PHP by Kevin McArthur p。 143楼。

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

    Traversable {
    }
    

    混淆部分是对象和数组实现“可遍历”,但 can be traversed 由 foreach 实现,但您不能使用 instanceof 检查 foreach 兼容性检查或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 遍历,但是您可以只访问公共属性。引用Object Iteration上的PHP手册:

    PHP 5 提供了一种定义对象的方法,因此可以 遍历项目列表,例如 foreach 陈述。默认情况下,所有可见属性都将用于 迭代。

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

    简而言之,实现 Traversable 接口(通过 Iterator 或 IteratorAggregate)的对象“就像一个数组”。但是,迭代对象不是必需的。但是如果你想改变他们的行为,你需要实现 Iterator。同样的逻辑也适用于内置类。

    【讨论】:

    • 您的回答与我问的问题中的 note 完全不同。您能否用问题中提出的简单词语解释一下注释
    • 感谢您的帮助。一件事让我很紧张,那个笔记中的foreach这个词。是否意味着内部内置类直接实现Traversable接口,不实现IteratorAggregate **或**Iterator接口,直接在Traversable中使用Traversable b>foreach 循环?或者可能是我错了,请你告诉我吗?
    • foreach这个词让我很困惑,不知道这个noteforeach的场景是什么。
    • 是的,一些用C编写的内部类可能会直接实现Traversable接口,在foreach循环中暴露私有字段、next()、key()等。但我不能为此举一个例子(AFAIK 主要是测试、资源类和一些 Zend 的东西)。 )
    猜你喜欢
    • 1970-01-01
    • 2017-07-28
    • 2020-09-09
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    相关资源
    最近更新 更多