上篇文章中我们讲了迭代器模式的原理、实现和设计意图。迭代器模式主要作用是解耦容器代码和遍历代码,这也印证了我们前面多次讲过的应用设计模式的主要目的是解耦。
其实在php中,PHP在php5版本后就已经在spl库内置了Iterator接口,以及大量的已经实现的迭代器,如数组,文件等遍历,今天我们就来讲解一些php中的迭代器。在讲解php的迭代器前我们先来了解一下PHP的spl。

spl简介

SPL (标准PHP库)是PHP 5面向对象功能中最重要的部分。它在5个关键的方面提升了PHP语言,包括:迭代器、异常、数组重载、XML以及文件和数据处理能力。它还提供了另外一些有用的项,例如观察者模式、计数功能、用于对象标识符的辅助函数以及迭代器处理功能。此外,它还提供了用于自动加载类和接口的高级功能。

spl迭代器接口与迭代器

SPL迭代器接口的作用在于帮助实现高级的迭代算法,允许为类创建精巧的数据访问方法。这些接口形成了创建迭代器类的基础。可以直接实现这些接口去创建所需的迭代器,不过,SPL扩展定义了更多的内置迭代器类,以完成最普通的迭代任务。我们先了解这些接口,然后再探讨其中一些内置的类。

迭代器接口

SPL提供了5个迭代器接口: Traversable、 Iterator、 IteratorAggregate、 OuterIteratorf 和 RecursiveIterator

1.Traversable
Traversable接口实际上不是一个接口,更像是一个特性。这是因为只有内部的类( 也就是用C语言编写的类)才可以直接实现Traversable接口。任何需要实现Traversabl e接口的用户自定义类都必须通过实现从Traversab1e接口派生的用户自定义接口来做到这一点。有两个派生自Traversable接口的基础级别的类,它们才是你的对象可以访问的接口,即Iterator 接口和 IteratorAggregate 接口。通过实现这两个接口之一,对象就可以和foreach语句一起使用了。

2.Iterator
Iterator接口是在c代码内部定义的,可在内部迭代自己的外部迭代器或类的接口。
Iterator接口定义如下:

interface Iterator extends Traversable {
/* 方法 */
abstract public current ( void ) : mixed
abstract public key ( void ) : scalar
abstract public next ( void ) : void
abstract public rewind ( void ) : void
abstract public valid ( void ) : bool
}

Iterator接口给我们提供了5个方法它们的作用具体如下:

方法说明
current()返回当前元素的值
key()返回当前的键名称或索引值
next()将数组指针向前一位指向下一个元素
rewind()将数组指针移动到数组的开头位置
valid()确定当前元素是否存在,并且必须在调用了next ()方法和rewind()方法之后才能调用这个方法

3.IteratorAggregate
IteratorAggregate接口是用来将Iterator接口要求实现的5个迭代器方法委托给其他类的。这让你可以在类的外部实现迭代功能,并允许重新使用常用的迭代器方法,而不是在编写的每个可迭代类中重复使用这些方法。IteratorAggregate接口定义如下:

interface IteratorAggregate extends Traversable {

    public function getIterator();
}

实现getIterator()方法时,必须返回一个实现了Iterator接口的类的实例。通常在getIterator ()方法内部,你会把类的信息传递给一个特殊的迭代器类的构造函数。这个数据可能是一个基础数组或者任何能够想到的其他数据,只要它足够控制5个Iterator方法即可。
SPL提供了一些专门用来 与IteratorAggregate接口一起使用的内置迭代器。使用这些迭代器意味着只需要实现一个方法并实例化一个类就可以使对象可迭代访问了。
如下代码就是ArrayIterator接口和IteratorAggregate接口一起使用的效果。


class MyIterableClass implements \IteratorAggregate {
    public $property1 = "Public property one";
    public $property2 = "Public property two";
    public $property3 = "Public property three";

    public function __construct() {
        $this->property4 = "last property";
    }

    public function getIterator() {
        return new \ArrayIterator($this);
    }

}

$obj = new MyIterableClass;

foreach($obj as $key => $value) {
    echo($key." --- ".$value);
    echo "<br>";
}

运行结果:

4. OuterIterator
有时,将一个或多个迭代器包裹在另外一个迭代器中是很有用的,例如,在你希望按顺序迭代访问几个不同的迭代器时对于这一用途而言,可以使用outerIterator接口。
outerIterator接口定义如下:

interface OuterIterator extends Iterator {

    public function getInnerIterator();
}

这个接口与IteratorAggregate接口的区别在于它扩展了Iterator接口,因此,所有实现它的类都必须实现Iterator接口定义的所有方法。
getInnerIterator ()方法应该返回当前正在迭代访问的迭代器。例如,当两个或者更多的迭代器被添加在-起并且一个接一个地迭代访问时,随着数组指针通过next ()方法不断增加,getInnerIterator ()方法必须返回第一个迭代器,然后是第二个,以此类推。
这一接口形成了其他几个更加专用的迭代器的基础接口,其中包括AppendIterator.CachingIterator、FilterIterator、 IteratorIterator、LimitIterator和RecursiveIteratorIterator接口。

5. RecursiveIterator
RecursiverIterator接口的作用在于提供了递归迭代访问功能。这种类型的迭代器接口可以表达一个树形的数据结构,其中包含了节点元素和叶子元素或者父元素和子元素。目录就是一个递归结构的例子。
RecursiveIterator接口定义如下:

interface RecursiveIterator extends Iterator {

    public function hasChildren();

    public function getChildren();
}

所有的递归函数(调用自身的函数)都必须具有这样的功能,即决定是要继续递归操作,还是停止递归并返回到调用栈的顶部。hasChildren()方法提供了实现这一判断条件的功能。如果迭代器拥有子元素, getChildren()方法将会被调用,并且它应该返回子元素的一个迭代器实例。

迭代器

SPL提供了几种迭代器,分别提供了迭代访问迭代器、过滤数据、缓存结果、控制分页等功能。
1.ArrayIterator
ArrayIterator迭代器可以说是SPL包中最强大的迭代器之一。它允许从php数组中创建迭代器这个迭代器。如下:

$arr = array('a','b','c','d');
$arrayIterator = new \ArrayIterator($arr);
foreach ($arrayIterator as $value){
    echo $value."\n";
}
//输出结果 a b c d

从这段代码并不能看出这个迭代器有多大作用,因为完全可以跳过创建迭代器的操作去实现同样的功能。不过,重要的是要理解如何从一个数组手工获得一个 迭代器,这是因为许多其他SPL迭代器的构造函数都需要传入一个迭代器,而不是数组。
当ArrayIterator迭代器和IteratorAggregate类一起使用时, 免去了直接实现Iterator接口的方法的工作。如果类使用-一个数组作为底层的表示方式,只需在getIterator ()方法中返回一个ArrayIterator接口即可。

2.LimitIterator
LimitIterator是一个比较简单的迭代器。它让你可以实现与SQL的LIMIT子句和OFFSET子句相同的迭代访问功能,它会返回给定数量的结果以及从集合中取出结果的起始索引点。LimitIterator迭代器实现了OuterIterator接口。
LimitIterator的构造函数接受3个参数:迭代器、偏移量和限制数量。用法如下:

$arr = array(1,2,3,4,5,6,7,8,9);
$arrayIterator = new \ArrayIterator($arr);
$limitIterator = new \LimitIterator($arrayIterator,3,4);
foreach ($limitIterator as $value){
    echo $value."\n";
}
//输出结果 4 5 6 7

3.AppendIterator
AppendIterator迭代器允许按顺序迭代访问几个不同的迭代器。例如,如果希望在一个循环中迭代访问两个或更多的数组,需要使用AppendIterator迭代器。用法如下:

$arrFirst = new \ArrayIterator(array(1,2,3));
$arrSecond = new \ArrayIterator(array(4,5,6));

$appendIterator = new \AppendIterator();
$appendIterator->append($arrFirst);
$appendIterator->append($arrSecond);

foreach ($appendIterator as $value) {
    echo $value."\n";
}
//输出结果 1 2 3 4 5 6

可以看到,添加迭代器的顺序正是迭代访问迭代器的顺序。由于这里使用AppendIterator迭代器,迭代访问所有数组只需要一个循环就可以了。

4.FilterIterator
FilterIterator类是一个基于outerIterator接口的迭代器。在迭代器中它被用来过滤数据,并且返回任何符合条件的元素。例如,FilterIterator类 可以和DirectoryIterator类一起使用,用来返回一个大文件列表。
这个类有一个 必须实现的抽象方法accept ()。正因为这点,FilterIterator类只能作为基类使用。accept ()方法必须为迭代器中的当前项返回true或者false。如果返回的结果是true,那么那条记录将被包含在迭代过程中。如果结果是false,它将被排除在外。
我们可以使用FilterIterator迭代器实现一个过滤功能,代码如下:

class GreaterThanThreeFilterIterator extends \FilterIterator {

    public function accept()
    {
       return ($this->current() > 3);
    }
}

$arr = new \ArrayIterator(array(1,2,3,4,5,6));
$iterator = new GreaterThanThreeFilterIterator($arr);
foreach ($iterator as $value) {
    echo $value."\n";
}

//输出结果 4 5 6

5.RegexIterator
RegexIterator是从FilterIterator类继承来的,它允许使用几种正则表达式模式来匹配和修改迭代器的数据集。
RegexIterator类最基本的用途是将字符串键值和数值与一个模式相匹配,并返回匹配的那些键值。下面是一个显示如何查找以字母a开头的所有项的代码示例。

$arr = array('apple','avocado','orange','pineapple');
$arrayIterator = new \ArrayIterator($arr);
$regexIterator = new \RegexIterator($arrayIterator,'/^a/');

print_r(iterator_to_array($regexIterator));//iterator_to_array — 将迭代器中的元素拷贝到数组

//输出结果  Array ( [0] => apple [1] => avocado )

与上面的简单匹配代码相比,RegexIterator类还提供了更多的功能,他有几个其他的参数,可以用来修改他的工作方式。RegexIterator的构造函数如下:

__construct ( Iterator $iterator , string $regex [, int $mode = self::MATCH [, int $flags = 0 [, int $preg_flags = 0 ]]] )

第一个值得注意的参数是$mode,它控制了正则表达式的操作模式。这个参数默认为RegexIterator:MATCH,但也可以是以下值之一。

  • GET_MATCH在这一模式中,迭代器的当前键值被传递给preg_match()函数的第三个参数。这会将当前键值替换为 &$matches数据。
  • ALL_MATCHES.这一选项和GET_MATCH是相同的,但它使用的是preg_match_all函数而不是preg_ _match函数。
  • SPLIT 这一模式使用preg_split函数,其含义与GET_MATCHALL_MATCHES是相同的。
  • REPLACE 这一选项接受当前的迭代器值,并且会执行正则表达式替换操作,然后使用替换后的字符串覆盖当前的值。

下面是将GET_MATCH作为$mode参数的用法

$arr = array('apple','avocado','orange','pineapple');
$arrayIterator = new \ArrayIterator($arr);
$regexIterator = new \RegexIterator($arrayIterator,'/^(a\w{3})\w*$/',RegexIterator::GET_MATCH);

print_r(iterator_to_array($regexIterator));

输出结果

上面的代码用到的正则表达式非常简单。它配置整个基于单词的字符串,这个字符串以字母a开头并且包含三个或更多的字符。括号内的模式(a/w{3})控制了字符串的哪一部分将被GET_MATCH模式所使用。在这个例子中,GET_MATCH模式使用的部分包括字母a和三个字符。最终的数组包含了位置0上整个匹配的字符串,接着是任何捕捉到的子模式。
下一个RegexIterator类的参数$flags允许通知迭代器要它处理数组的键值还是数组的值。默认情况下是使用数组的值,不过,可以给这个参数传入类的常量USE_KEY以启用键值操作。
下面的代码显示如何使用RegexIterator类过滤一个 数组,使得数组中只包含键值为数字的项。最终的数组将只包含数字键值以及与数字键值相关联的值。

$arr = array('0'=>'A','1'=>'B','2'=>'C','3'=>'D','nonnumeric'=>'useless');
$arrayIterator = new \ArrayIterator($arr);
$regexIterator = new \RegexIterator(
            $arrayIterator,
            '/^\d*$/',
            RegexIterator::MATCH,
            RegexIterator::USE_KEY);

print_r(iterator_to_array($regexIterator));
//输出结果  Array ( [0] => A [1] => B [2] => C [3] => D )

RegexIterator类的最后一个参数$preg_flags是用来向内部的preg函数传入所需的preg参数的。

6.IteratorIterator
一开始理解IteratorIterator迭代器是比较困难的,但实际上它是SPL提供的最酷的迭代器之一。IteratorIterator是一种通用类型的迭代器,这意味着所有实现了Traversable接口的类都可以被它迭代访问。起初,这看起来并不是很有用,但是在多种PHP的扩展中都会有一些类没有实现Iterator接口或者IteratorAggregate接口,但却实现了Traversable接口。
其中的一个例子是PDO (PHP数据对象)扩展。在PDO中,PDOStatement类 只实现了Traversable接口,这是因为它是一个只读集合,也正因为如此,实现高层次的迭代器接口是不合适的。这一只读限制的结果是,要将PDOStatement类的结果和本章描述过的任何其他迭代器相结合,需要使用IteratorIterator迭代器去封装PDOStatement类。
由于PDOStatement类的只读特性,使用像RegexIterator这样的可修改的迭代器可能会带来问题,所以不应该在PDOStatement类上使用这些迭代器。也就是说,像AppendIterator、FilterIterator和LimitIterator这样功能强大的迭代器在与pDoStatement结果集组合在一起使用时,将会非常有用。下面的代码显示了如何使用IteratorIterator迭代器和LimitIterator迭代器来限制结果集。

$db = new \PDO( 'pgsql:dbname=yourdb; user=youruser') ;
$pdoStatement = $db->query( ' SELECT * FROM table') ;
$iterator = new \IteratorIterator ($pdoStatement) ;
$limitIterator = new \LimitIterator ($iterator , 0, 10) ;
$tenRecordArray = iterator_to_array($limitIterator) ;

说明:上面代码只作为演示用途。如果希望限制结果集只包含十条记录,那么应该在SQL查询语句中使用SQL LIMIT语法。

7.CachingIterator
CachingIterator迭代器用来执行提前读取一个元素的迭代操作。在迭代循环的某一特定点上,当需要了解关于下一个元素的信息时,这些迭代器会非常有用。例如,可以使用这一迭代器来确定当前元素是否为列表中的最后一个元素。使用递归形式,可以在一个树形结构中通过查找关于下一个键值的信息来确定当前节点是节点还是项。

$iterator = new \CachingIterator(new ArrayIterator(['C', 'C++', 'C#', 'PHP', 'Python', 'Go', 'Ruby']));

foreach ($iterator as $item) {
    if ($iterator->hasNext()) {
        echo $item.', ';
    } else {
        echo 'and '.$item;
    }
}
//输出结果 : C, C++, C#, PHP, Python, Go, and Ruby

8.SeekableIterator
SeekableIterator迭代器可用于创建非顺序访问的迭代器。它允许跳转到迭代器中的任何一点上,而不用迭代访问所有这一点之前的元素。

$array = array('a','b','c','d');

//ArrayIterator 实现了接口 SeekableIterator

$iterator = new ArrayIterator($array);
$iterator->seek(3);
echo $iterator->current();
//输出结果 d

9.NoRewindIterator
NoRewindIterator迭代器可用于不能回卷的集合,或者说是不能多次迭代的集合。当你需要在迭代过程中执行一次性操作时,这种迭代器非常有用。例如,在迭代过程中插入数据库记录时。

$iterator = new \ArrayIterator(['PHP', 'Python', 'Go']);
$iterator = new \NoRewindIterator($iterator);

foreach ($iterator as $item) {
    echo $item.PHP_EOL;
}

// doesn't do anything
foreach ($iterator as $item) {
    echo $item.PHP_EOL;
}

//输出结果 :  PHP Python Go

10.EmptyIterator
EmptyIterator是一种占位符形式的迭代器,它不执行任何操作。当要实现某个抽象类的方法并且这个方法需要返回一个迭代器时,可以使用这一迭代器。它也可以用于执行迭代器之间的比较操作

11.InfiniteIterator
InfiniteIterator迭代器用来持续地循环访问数据。当迭代操作找到最后一个元素时,迭代器会回卷,并再次从第一个元素开始迭代访问数据。

$obj = new stdClass();
$obj->Mon = "Monday";
$obj->Tue = "Tuesday";
$obj->Wed = "Wednesday";
$obj->Thu = "Thursday";
$obj->Fri = "Friday";
$obj->Sat = "Saturday";
$obj->Sun = "Sunday";

$infiniteIterator = new InfiniteIterator(new ArrayIterator($obj));
foreach ( new LimitIterator($infiniteIterator, 0, 14) as $value ) {
    print($value . PHP_EOL);
}

/*
输出结果
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
 */

12.RecursiveArrayIterator
RecursiveArrayIterator迭代器允许创建一个用于递归形式数组结构(类似于多维数组)的迭代器。这是一个很重要的迭代器,因为它为许多更复杂的迭代器提供了所需的操作,如RecursiveTreeIterator迭代器和RecursiveArrayIterator迭代器
下面是RecursiveArrayIterator 迭代器的用法:

$arr = array (
    0=> 'a' ,
    1 => array('a','b', 'c') ,
    2 => 'b',
    3 => array('a', 'b', 'c') ,
    4 => 'c'
);
$it = new \RecursiveArrayIterator ($arr) ;

while ($it->valid()) {
    //检查是否含有子节点
    if($it->hasChildren()){
        //输出所有子节点
        foreach ($it->getChildren() as $key => $value) {
            echo $key.'---'.$value."<br>";
        }
    }else{
        echo"No children.<br>";
    }
    $it->next();
}

/**
运行结果
No children.
0---a
1---b
2---c
No children.
0---a
1---b
2---c
 */

13.RecursiveIteratorIterator
RecursiveIteratorIterator允许获得一个树形结构,并将它展开为一维结构,当这个迭代器发现一个子迭代器时,它会访问这个子迭代器。

$arr = array (
    0=> 'a' ,
    1 => array('a','b', 'c') ,
    2 => 'b',
    3 => array('a', 'b', 'c') ,
    4 => 'c'
);
$arrayIterator = new \RecursiveArrayIterator ($arr) ;

$it = new \RecursiveIteratorIterator($arrayIterator);
print_r(iterator_to_array($it,false));

/*
 运行结果:
Array
(
    [0] => a
    [1] => a
    [2] => b
    [3] => c
    [4] => b
    [5] => a
    [6] => b
    [7] => c
    [8] => c
)
 */

可以看到上一个代码运行的结果得到的就是一个一维数组
RecursiveIteratorIterator迭代器的构造函数如下:

public RecursiveIteratorIterator::__construct ( Traversable $iterator [, int $mode = RecursiveIteratorIterator::LEAVES_ONLY [, int $flags = 0 ]] )

$mode参数可以接受以下三个类常量之一: CHILD_FIRSTSELF_FIRST 或者默认的 JEAVES_ONLY
这一模式参数控制节点是否包含在树中以及它们是以何种顺序包含在树中。例如,一个目录结构最好被打印成一个SELF_FIRST形 式的树,但是在搜索文件时,使用LEAVES_ONLY会更合理一些。
$flags参数可以被设置为CATCH_GET_CHILDREN,可以在调用子迭代器时捕获所有的异常,并且在抛出异常时继续访问下一个元素。

14.RecursiveTreeIterator
RecursiveTreeIterator 不是一个内置的迭代器,它是example目录中的/ext/spl/examples/recursivetreeiterator.inc文件中的SPL扩展提供的一个示例迭代器。使用这个迭代器,可以显示一个树形结构

$arr = array (
    0=> 'a' ,
    1 => array('a','b', 'c') ,
    2 => 'b',
    3 => array('a', 'b', 'c') ,
    4 => 'c'
);
$arrayIterator = new \RecursiveArrayIterator ($arr) ;

$it = new \RecursiveTreeIterator($arrayIterator);
print_r(iterator_to_array($it,false));

/*
运行结果:
Array
(
    [0] => |-a
    [1] => |-Array
    [2] => | |-a
    [3] => | |-b
    [4] => | \-c
    [5] => |-b
    [6] => |-Array
    [7] => | |-a
    [8] => | |-b
    [9] => | \-c
    [10] => \-c
)
 */

RecursiveTreeIterator迭代器和所有内含的示例迭代器一样都是用于扩展的。并没有要求树形结构迭代器必须输出基于文本的分界符。构造一个输出HTML形式的树形结构的迭代器也是可以的。

15.ParentIterator
ParentIterator是一个扩展的FilterIterator迭代器,(它可以过滤掉来自于RecursiveIterator迭代器的非父元素,从而只找出拥有子元素的键值)

$arr = array (
    0=> 'a' ,
    1 => array('a','b', 'c') ,
    2 => 'b',
    3 => array('a', 'b', 'c') ,
    4 => 'c'
);
$arrayIterator = new \RecursiveArrayIterator ($arr) ;

$it = new \ParentIterator($arrayIterator);
print_r(iterator_to_array($it,false));

/*
 运行结果:
Array
(
    [0] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )
    [1] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )
)
 */

16.RecursiveFilterIterator
RecursiveFilterIterator迭代器是FilterIterator迭代器的递归形式。与之前的迭代器一样,它要求实现抽象的accept()方法,但是在这个方法中,应该使用$this->getInnerIterator()方法访问当前正在迭代的迭代器。

17.RecursiveRegexIterator
RecursiveRegexIterator迭代器是RegexIterator迭代器的递归形式。它和RegexIterator迭代器的用法一样,不同的是它只能接受RecursiveIterator迭代器作为迭代的对象。

18.RecursiveCachingIterator
RecursiveCachingIterator迭代器在RecursiveIterator迭代器上执行提前读取一个元素的递归操作。在确定当前迭代的项是叶子还是节点时,它非常有用。

19.CallbackFilterIterator
同时执行过滤和回调操作,在找到一个匹配的元素之后会调用回调函数


$arr = array(1,2,3,4,5,6);
$arrayIterator = new \RecursiveArrayIterator($arr);
function GreaterThanThree($current)
{
    return $current > 3 != false;
}

$rs = new \CallbackFilterIterator($arrayIterator, 'GreaterThanThree');
print_r(iterator_to_array($rs));

/*
 输出结果
Array
(
    [3] => 4
    [4] => 5
    [5] => 6
)
 */

20.DirectoryIterator
DirectoryIterator类提供了一个简单的接口,用于查看文件系统目录的内容

方法描述
DirectoryIterator::getSize得到文件大小
DirectoryIterator::getType得到文件类型
DirectoryIterator::isDir如果当前项是一个目录,返回true
DirectoryIterator::isDot如果当前项是.或..,返回true
DirectoryIterator::isExecutable如果文件可执行,返回true
DirectoryIterator::isFile如果文件是一个常规文件,返回true
DirectoryIterator::isLink如果文件是一个符号链接,返回true
DirectoryIterator::isReadable如果文件可读,返回true
DirectoryIterator::isWritable如果文件可写,返回true
DirectoryIterator::key返回当前目录项
DirectoryIterator::next移动到下一项
DirectoryIterator::rewind将目录指针返回到开始位置
DirectoryIterator::valid检查目录中是否包含更多项
foreach (new DirectoryIterator('../') as $fileInfo) {
    if($fileInfo->isDot()) continue;
    echo $fileInfo->getFilename() . "<br>\n";
}

21.RecursiveDirectoryIterator
RecursiveDirectoryIterator提供了一个接口,用于在文件系统目录上递归迭代。

22.FilesystemIterator
FilesystemIterator是继承于DirectoryIterator的遍历器

23.GlobIterator
GlobIterator是一个带匹配模式的文件遍历器

$iterator = new \GlobIterator('*.php');
if (!$iterator->count()) {
    echo'无php文件';
} else {
    $n = 0;
    printf("总计 %d 个php文件\r\n", $iterator->count());
    foreach ($iterator as $item) {
        printf("[%d] %s\r\n", ++$n, $iterator->key());
    }
}

/*
 输出结果
总计 18 个php文件
[1] AppendIterator.php
[2] ArrayIterator.php
[3] CachingIterator.php
[4] CallbackFilterIterator.php
[5] DirectoryIterator.php
[6] GlobIterator.php
[7] GreaterThanThreeFilterIterator.php
[8] InfiniteIterator.php
[9] IteratorIterator.php
[10] LimitIterator.php
[11] MyIterableClass.php
[12] NoRewindIterator.php
[13] ParentIterator.php
[14] RecursiveArrayIterator.php
[15] RecursiveIteratorIterator.php
[16] RecursiveTreeIterator.php
[17] RegexIterator.php
[18] SeekableIterator.php
 */

24. MultipleIterator
对所有附加迭代器进行顺序迭代的迭代器

$person_id = new \ArrayIterator(array('001', '002', '003'));
$person_name = new \ArrayIterator(array('张三', '李四', '王五'));
$person_age = new \ArrayIterator(array(22, 23, 11));
$mit = new \MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
$mit->attachIterator($person_id, "ID");
$mit->attachIterator($person_name, "NAME");
$mit->attachIterator($person_age, "AGE");
echo"连接的迭代器个数:".$mit->countIterators() . "\n";
foreach ($mit as $person) {
    print_r($person);
}

/*
 输出结果
连接的迭代器个数:3
Array
(
    [ID] => 001
    [NAME] => 张三
    [AGE] => 22
)
Array
(
    [ID] => 002
    [NAME] => 李四
    [AGE] => 23
)
Array
(
    [ID] => 003
    [NAME] => 王五
    [AGE] => 11
)
 */

25.RecursiveCallbackFilterIterator
在RecursiveIterator迭代器上进行递归操作,同时执行过滤和回调操作,在找到一个匹配的元素之后会调用回调函数。

总结

本篇文章讲解了SPL的迭代器,它可以为复杂的编程问题提供优良的解决方法。
为了使用foreach控制循环访问对象,你的类必须实现Traversable接口,但不能直接实现Traversable接口,而必须通过Iterator接口或者IteratorAggregate接口实现它。Iterator接口要求实现所有的迭代器方法。IteratorAggregate接 口允许将这些方法的实现放到其他类中。作为示例,你看到了如何使用内置的ArrayIterator迭代器迭代访问基于数组的集合,而且只需要实现IteratorAggregate接口中要求的getIterator()方法即可。SPL还提供了更为复杂的迭代器接口,其中包括RecursiveIterator、OuterIterator和seekableIterator。
SPL提供了一系列实现了迭代器接口的迭代器类,可用于解决常见的编程难题。值得注意的是ArrayIterator、LimitIterator、FilterIterator和RegexIterator等迭代器以及它们的
递归形式。

代码示例:
https://github.com/yangpanyao/design-patterns/tree/master/Iterator/example2

Last modification:July 15th, 2020 at 09:31 pm