为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
PHP

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交给它的数据全部遍历出来。

点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消