SPL迭代器接口(四)—IteratorAggregate Interface

  IteratorAggregate Interface: 直接继承自Traversable接口的两个基本迭代器接口之一,允许将迭代器所需实现方法委托给一个实现Iterator接口的迭代器

  IteratorAggregate接口与Iterator接口一样继承自Traversable接口。IteratorAggregate接口是用来将Iterator接口要求实现的5个迭代器方法委托给其他类的。它可以让你在类的外部实现迭代功能,并允许重新使用常用的迭代器方法,而不是在编写的每个可迭代类中重复这些方法。

  简单来说,实现IteratorAggregate接口的类和实现Iterator接口的类一样也是一个迭代器,不过它不需要实现Iterator接口的5个要求实现的方法,它只需实现getIterator方法把Iterator接口要求实现的方法委托给一个已经实现的迭代器。

  实现一个迭代器前,必需先实现另一个迭代器?有点绕是吧。我们看代码就明白了。

  代码示例:

‹?php
//自定义迭代器实现IteratorAggregate接口
class MyIteratorAggregate implements IteratorAggregate{
    protected $arr = array(1,2,3);
    //IteratorAggregate接口要求实现的方法
    public function getIterator(){
        //返回一个实现Iterator接口类的实例
        return new MyIterator($this->arr);
    }
}

//MyIterator实现Iterator接口,Iterator接口那节讲过。
//这里我们做点修改,让它能接收外部数据,实际上就是实现__construct方法
class MyIterator implements Iterator
{
    protected $data = array();  //存放数据
    protected $index ;         //存放当前指针
    //构造方法接收外部传入数据
    public function __construct(Array $data)
    {   
        $this->data = $data;
    }
    //返回当前指针指向数据
    public function current()
    {   
        return $this->data[$this->index];
    }
    //指针+1
    public function next()
    {   
        $this->index ++;
    }
    //验证指针是否越界
    public function valid()
    {   
        return $this->index ‹ count($this->data);
    }
    //重置指针
    public function rewind()
    {   
        $this->index = 0;
    }
    //返回当前指针
    public function key()
    {   
        return $this->index;
    }
}
//实例化一个迭代器
$container = new MyIteratorAggregate;
//使用MyIteratorAggregate迭代器
foreach($container as $key => $val){
    echo $val.PHP_EOL;
}

  运行结果:

  也许你会说,这功能不是和实现Iterator接口的迭代器一样么?是的,我们想一下如果有十个要实现迭代器类,我们如果都实现Iterator接口的话,那么这十个类都要实现Iterator接口要求实现的5个方法。这些类中都重复了这5个方法,代码不是很冗余吗?

  所以我们只需先写一个实现Iterator接口的类,再让这十个迭代器类实现IteratorAggregate接口,代码不就简洁多了吗?

  而且美妙地是,SPL内置的迭代器类中,已经有一个实现Iterator接口ArrayIterator类,它仿佛就是专门为了给实现IteratorAggregate接口的getIterator方法而存在的。也就是说我们实现getIterator方法其实不需要直接写一个实现Iterator接口的类,直接使用SPL内置的ArrayIterator就可以了。

public function getIterator(){
        //返回一个实现Iterator接口类的实例
        return new ArrayIterator($this->arr);
    }

  当然,为了探究实现IteratorAggregate接口的迭代器是如何工作的,我们还是暂时还是使用我们自己实现的MyIterator类。

  那么,foreach的时候,实现IteratorAggregate接口的迭代器是怎么工作的呢?它为什么能只实现getIterator方法就可以实现迭代呢?
老规矩 ,我们在MyIteratorAggregate和MyIterator方法中,加上这一句

echo __METHOD__,PHP_EOL;
‹?php
//自定义迭代器实现IteratorAggregate接口
class MyIteratorAggregate implements IteratorAggregate{
    protected $arr = array(1,2,3);
    //IteratorAggregate接口要求实现的方法
    public function getIterator(){
        echo __METHOD__,PHP_EOL;
        //返回一个实现Iterator接口类的实例
        return new MyIterator($this->arr);
    }
}

//MyIterator实现Iterator接口,Iterator接口那节讲过。
//这里我们做点修改,让它能接收外部数据,实际上就是实现__construct方法
class MyIterator implements Iterator
{
    protected $data = array();  //存放数据
    protected $index ;         //存放当前指针
    //构造方法接收外部传入数据
    public function __construct(Array $data)
    {   
        echo __METHOD__,PHP_EOL;
        $this->data = $data;
    }
    //返回当前指针指向数据
    public function current()
    {   
        return $this->data[$this->index];
    }
    //指针+1
    public function next()
    {   
        echo __METHOD__,PHP_EOL;
        $this->index ++;
    }
    //验证指针是否越界
    public function valid()
    {   
        echo __METHOD__,PHP_EOL;
        return $this->index ‹ count($this->data);
    }
    //重置指针
    public function rewind()
    {   
        echo __METHOD__,PHP_EOL;
        $this->index = 0;
    }
    //返回当前指针
    public function key()
    {   
        echo __METHOD__,PHP_EOL;
        return $this->index;
    }
}
//实例化一个迭代器
$container = new MyIteratorAggregate;
//使用MyIteratorAggregate迭代器
foreach($container as $key => $val){
    echo $val.PHP_EOL;
}

  运行结果

  我们结果就跟我们意料中的一样foreach的时候,PHP自动调用了MyIteratorAggregate的getIterator方法,然后实例化一个MyIterator对象,调用它的构造方法并把MyIteratorAggregate的数据$arr交给它。接下去就把迭代的事情委托给MyIterator对象了,所以我们看到后面又是顺序调用rewind->valid->current->key->next………..直到把MyIteratorAggregate交给它的数据全部遍历出来。

来源:慕课手记 https://www.imooc.com/article/17901

转载请注明出处:https://www.onexin.net/spl-iteratoraggregate-interface/

相关文章:

1、SPL迭代器接口(六)—RecursiveIterator Interface
https://www.onexin.net/spl-recursiveiterator-interface/

2、SPL迭代器接口(五)—OuterIterator Interface
https://www.onexin.net/spl-outeriterator-interface/

3、SPL迭代器接口(三)—SeekableIterator Interface
https://www.onexin.net/spl-seekableiterator-interface/

4、SPL迭代器接口(二)—Iterator Interface
https://www.onexin.net/spl-iterator-interface/

5、SPL迭代器接口(一)—Traversable Interface
https://www.onexin.net/spl-traversable-interface/

Leave a Reply