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交给它的数据全部遍历出来。
共同学习,写下你的评论
评论加载中...
作者其他优质文章