OuterIterator Interface: 继承自Iterator接口,允许将多个迭代器包裹其中。
OuterIterator接口继承自Iterator接口。实现OuterIterator接口的迭代器类,允许将一个或多个迭代器包裹其中,并按顺序访问这些迭代器。
OuterIterator比Iterator多了一个getInnerIterator方法,该方法根据定义的返回值类型,可以知道应该返回当前正在访问的迭代器。
OuterIterator与IteratorAggregate不一样,foreach的时候PHP是不会自动调用getInnerIterator方法的,我刚开始实现这个接口的时候就是以为foreach会自动调用。以为直接返回当前指向的迭代器,就能想IteratorAggregate那样,把迭代器遍历出来。
但是,实际上并不行。网上这方面的资料比较少。我参考了PHP源码里的内置的IteratorIterator迭代器和AppendIterator迭代器,实现了OuterIterator接口。代码如下,欢迎大家交流指正。
代码示例:
<?php
//自定义MyOuterIterator实现OuterIterator接口
class MyOuterIterator implements OuterIterator{
protected $iterators = array(); //存放迭代器
protected $index; //存放当前迭代器指针
//构造方法,接收外部传入的迭代器
public function __construct(Array $iterators){
$this->iterators = $iterators;
}
//返回当前正在访问的迭代器
public function getInnerIterator(){
return $this->iterators[$this->index];
}
//返回当前指针指向数据
public function current()
{
echo __METHOD__,PHP_EOL;
//返回当前指针指向MyIterator迭代器的指针,指向数据
return $this->getInnerIterator()->current();
}
//数据指针+1
public function next()
{
echo __METHOD__,PHP_EOL;
//当前指针指向MyIterator迭代器的指针,即数据指针+1
$this->getInnerIterator()->next();
//判断该数据指针是否越界,如果越界,则把迭代器指针下一个MyIterator迭代器。
if(!$this->getInnerIterator()->valid()){
//不判断是否小于count($this->iterators)的话,自增若越界会引起MyIterator初始化指针报错
++$this->index < count($this->iterators) && $this->getInnerIterator()->rewind();
}
}
//验证指针是否越界
public function valid()
{
echo __METHOD__,PHP_EOL;
return $this->index < count($this->iterators);
}
//重置指针
public function rewind()
{
$this->index = 0;
//初始化MyIterator迭代器指针
$this->getInnerIterator()->rewind();
}
//返回当前指针
public function key()
{
echo __METHOD__,PHP_EOL;
//获取MyIterator指针
$key = $this->getInnerIterator()->key();
//为避免不同MyIterator迭代器实例有相同的key值,拼上前缀(迭代器存放位置下标)
return $this->index.'-'.$key;
}
}
//自定义的MyIterator类
class MyIterator implements Iterator
{
protected $data = array(); //存放数据
protected $index=0 ; //存放当前指针
//构造方法接收外部传入数据
public function __construct(Array $data)
{
$this->data = $data;
}
//返回当前指针指向数据
public function current()
{
echo __METHOD__,PHP_EOL;
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;
}
}
$arr1=array(1,2);
$arr2=array(3,4);
$iterators = array(new MyIterator($arr1),new MyIterator($arr2));
//实例化一个MyOuterIterator迭代器
$container = new MyOuterIterator($iterators);
//使用MyOuterIterator迭代器
foreach($container as $key => $val){
echo $key.'=>'.$val.PHP_EOL;
}
运行结果:
遗憾地是,上面的代码可以顺序访问不同类型迭代器,但局限于这些迭代器都是实现Iterator接口的迭代器。不能访问实现IteratorAggregate接口的迭代器。
下面是实现方式可以顺序访问实现IteratorAggregate接口的不同类型迭代器,同样遗憾地是,它不支持实现Iterator接口的迭代器。
代码示例:
//自定义MyOuterIterator实现OuterIterator接口
class MyOuterIterator implements OuterIterator{
protected $iterators = array(); //存放迭代器
protected $index; //存放当前迭代器指针
protected $iterator; //存放当前MyIteratorAggregate生成的MyIterator迭代器
//构造方法,接收外部传入的迭代器
public function __construct(Array $iterators){
$this->iterators = $iterators;
}
//返回当前正在访问的迭代器
public function getInnerIterator(){
return $this->iterator;
}
//返回当前指针指向数据
public function current()
{
echo __METHOD__,PHP_EOL;
//返回当前指针指向MyIterator迭代器的指针,指向数据
return $this->getInnerIterator()->current();
}
//数据指针+1
public function next()
{
echo __METHOD__,PHP_EOL;
//当前指针指向MyIterator迭代器的指针,即数据指针+1
$this->getInnerIterator()->next();
//判断该数据指针是否越界,如果越界,则把迭代器指针下一个MyIteratorAggregate迭代器。
if(!$this->getInnerIterator()->valid()){
//不判断是否小于count($this->iterators)的话,自增若越界会引起MyIterator初始化指针报错
if(++$this->index < count($this->iterators)){
$this->iterator = $this->iterators[$this->index]->getIterator();
$this->iterator->rewind();
}
}
}
//验证指针是否越界
public function valid()
{
echo __METHOD__,PHP_EOL;
return $this->index < count($this->iterators);
}
//重置指针
public function rewind()
{
$this->index = 0;
$this->iterator = $this->iterators[$this->index]->getIterator();
//初始化MyIterator迭代器指针
$this->getInnerIterator()->rewind();
}
//返回当前指针
public function key()
{
echo __METHOD__,PHP_EOL;
//获取MyIterator指针
$key = $this->getInnerIterator()->key();
//为避免不同MyIterator迭代器实例有相同的key值,拼上前缀(迭代器存放位置下标)
return $this->index.'-'.$key;
}
}
//自定义的MyIterator类
class MyIterator implements Iterator
{
protected $data = array(); //存放数据
protected $index=0 ; //存放当前指针
//构造方法接收外部传入数据
public function __construct(Array $data)
{
$this->data = $data;
}
//返回当前指针指向数据
public function current()
{
echo __METHOD__,PHP_EOL;
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;
}
}
//自定义迭代器实现IteratorAggregate接口
class MyIteratorAggregate implements IteratorAggregate{
protected $arr = array();
public function __construct($arr){
$this->arr = $arr;
}
//IteratorAggregate接口要求实现的方法
public function getIterator(){
echo __METHOD__,PHP_EOL;
//返回一个实现Iterator接口类的实例
return new MyIterator($this->arr);
}
}
$arr1=array(1,2);
$arr2=array(3,4);
$iterators = array(new MyIteratorAggregate($arr1),new MyIteratorAggregate($arr2));
//实例化一个MyOuterIterator迭代器
$container = new MyOuterIterator($iterators);
//使用MyOuterIterator迭代器
foreach($container as $key => $val){
echo $key.'=>'.$val.PHP_EOL;
}
运行结果:
感觉有点复杂,可能我打开的方式不对,大家如果有可以同时支持Iterator和IteratorAggregate的实现方法,麻烦联系我(fxlxzf10@163.com
),让我也能学习。谢谢。
庆幸地是,PHP中已经有一个内置的实现OuterIterator接口,可以顺序访问不同类型迭代器的迭代器。它就是AppendIterator
迭代器,继承自IteratorIterator
迭代器。
AppendIterator并没有直接实现OuterIterator,但它的父类IteratorIterator实现了OuterIterator。关于AppendIterator和IteratorIterator,我将会在SPL内置迭代器中介绍。欢迎大家到时候交流指正
OuterIterator接口通常很少直接实现,经常是通过继承IteratorIterator。