PHP设计模式之迭代器模式的深入解析


Posted in PHP onJune 13, 2013

迭代器(Iterator)模式,它在一个很常见的过程上提供了一个抽象:位于对象图不明部分的一组对象(或标量)集合上的迭代。迭代有几种不同的具体执行方法:在数组属性,集合对象,数组,甚至一个查询结果集之上迭代。

在对象的世界里,迭代器模式要维持类似数组的功能,看作是一个非侵入性对象刻面(facet),Client类往往分离自真实对象实现,指iterator接口。只要有可能,我们可以给迭代器传送一个引用,代替将来可能发生变化的具体或抽象类。
PHP设计模式之迭代器模式的深入解析
参与者:
◆客户端(Client):
引用迭代器模式的方法在一组值或对象上执行一个循环。
◆迭代器(Iterator):在迭代过程上的抽象,包括next(),isFinished(),current()等方法。
◆具体迭代器(ConcreteIterators):在一个特定的对象集,如数组,树,组合,集合等上实现迭代。
通过Traversable接口,PHP原生态支持迭代器模式,这个接口由Iterator和IteratorAggregate做了扩展,这两个子接口不仅是定义了一套标准的方法,每个Traversable对象都可以原封不动地传递给foreach(),foreach是迭代器的主要客户端,Iterator实现是真正的迭代器,而IteratorAggregate是有其它职责的Traversable对象,它通过getIterator()方法返回一个Iterator。

PHP设计模式之迭代器模式的深入解析

标准PHP库是PHP中绑定的唯一通用目的面向对象库,定义了额外的接口和公用类。OuterIterator实现装饰一个Iterator,CachingIterator和LimitIterator是这个接口的两个例子。

RecursiveIterator是Iterator接口为树形结构实现的一个扩展,它定义了一组额外的方法检查迭代中当前元素的子对象是否存在。RecursiveArrayIterator和RecursiveDirectoryIterator是这个接口的实现示例,这些类型的迭代器可以原样使用,或是用一个RecursiveIteratorIterator桥接到一个普通的迭代器契约。这个OuterIterator实现将会根据构造参数执行深度优先或广度优先遍历。

使用RecursiveIteratorIterator时,可以将其传递给foreach,请看后面的代码示例,了解RecursiveIterators的不同用法和它们的超集Iterator。最后,SeekableIterators向契约添加了一个seek()方法,它可以用于移动Iterator的内部状态到一个特定的迭代点。 

注意,迭代器是比对象集更好的抽象,因为我们可以让InfiniteIterators,NoRewindIterators等,不用与普通数组阵列一致,因此,Iterator缺少count()函数等功能。

在PHP官方手册中可以找到完整的SPL迭代器列表。得益于对PHP的强力支持,使用迭代器模式的大部分工作都包括在标准实现中,下面的代码示例就利用了标准Iterator和RecursiveIterators的功能。

    <?php 
    /**  
     * Collection that wraps a numeric array.  
     * All five public methods are needed to implement  
     * the Iterator interface.  
     */  
    class Collection implements Iterator  
    {  
 private $_content;  
 private $_index = 0;   public function __construct(array $content)  
 {  
     $this->_content = $content;  
 }  
 public function rewind()  
 {  
     $this->_index = 0;  
 }  
 public function valid()  
 {  
     return isset($this->_content[$this->_index]);  
 }  
 public function current()  
 {  
     return $this->_content[$this->_index];  
 }  
 public function key()  
 {  
     return $this->_index;  
 }  
 public function next()  
 {  
     $this->_index++;  
 }  
    }  
    $array = array('A', 'B', 'C', 'D');  
    echo "Collection: ";  
    foreach (new Collection($array) as $key => $value) {  
 echo "$key => $value. ";  
    }  
    echo "\n"; 
    /**  
     * Usually IteratorAggregate is the interface to implement.  
     * It has only one method, which must return an Iterator  
     * already defined as another class (e.g. ArrayIterator)  
     * Iterator gives a finer control over the algorithm,  
     * because all the hook points of Iterator' contract  
     * are available for implementation.  
     */  
    class NumbersSet implements IteratorAggregate  
    {  
 private $_content;  
 public function __construct(array $content)  
 {  
     $this->_content = $content;  
 }  
 public function contains($number)  
 {  
     return in_array($number, $this->_content);  
 }  
 /**  
  * Only this method is necessary to implement IteratorAggregate.  
  * @return Iterator  
  */  
 public function getIterator()  
 {  
     return new ArrayIterator($this->_content);  
 }  
    }  
    echo "NumbersSet: ";  
    foreach (new NumbersSet($array) as $key => $value) {  
 echo "$key => $value. ";  
    }  
    echo "\n"; 
    // let's play with RecursiveIterator implementations  
    $it = new RecursiveArrayIterator(array(  
 'A',  
 'B',  
 array(  
     'C',  
     'D'  
 ),  
 array(  
     array(  
  'E',  
  'F'  
     ),  
     array(  
  'G',  
  'H',  
  'I'  
     )  
 )  
    ));  
    // $it is a RecursiveIterator but also an Iterator,  
    // so it loops normally over the four elements  
    // of the array.  
    echo "Foreach over a RecursiveIterator: ";  
    foreach ($it as $value) {  
 echo $value;  
 // but RecursiveIterators specify additional  
 // methods to explore children nodes  
 $children = $it->hasChildren() ? '{Yes}' : '{No}';  
 echo $children, ' ';  
    }  
    echo "\n";  
    // we can bridge it to a different contract via  
    // a RecursiveIteratorIterator, whose cryptic name  
    // should be read as 'an Iterator that spans over  
    // a RecursiveIterator'.  
    echo "Foreach over a RecursiveIteratorIterator: ";  
    foreach (new RecursiveIteratorIterator($it) as $value) {  
 echo $value;  
    }  
    echo "\n";
PHP 相关文章推荐
E路文章系统PHP
Dec 11 PHP
基于php-fpm的配置详解
Jun 03 PHP
PHP register_shutdown_function函数的深入解析
Jun 03 PHP
PHP队列用法实例
Nov 05 PHP
php实现多维数组中每个单元值(数字)翻倍的方法
Feb 16 PHP
laravel 5 实现模板主题功能(续)
Mar 02 PHP
php简单日历函数
Oct 28 PHP
PHP二分查找算法示例【递归与非递归方法】
Sep 29 PHP
解决Laravel自定义类引入和命名空间的问题
Oct 15 PHP
详解laravel passport OAuth2.0的4种模式
Nov 04 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
Nov 26 PHP
HTTP头隐藏PHP版本号实现过程解析
Dec 09 PHP
PHP设计模式之解释器模式的深入解析
Jun 13 #PHP
PHP设计模式之代理模式的深入解析
Jun 13 #PHP
PHP设计模式之责任链模式的深入解析
Jun 13 #PHP
PHP设计模式之结构模式的深入解析
Jun 13 #PHP
PHP设计模式之命令模式的深入解析
Jun 13 #PHP
深入Memcache的Session数据的多服务器共享详解
Jun 13 #PHP
探讨:如何使用PHP实现计算两个日期间隔的年、月、周、日数
Jun 13 #PHP
You might like
自动分页的不完整解决方案
2007/01/12 PHP
php常用Output和ptions/Info函数集介绍
2013/06/19 PHP
PHP微信企业号开发之回调模式开启与用法示例
2017/11/25 PHP
Laravel如何自定义command命令浅析
2019/03/23 PHP
PHP使用PhpSpreadsheet操作Excel实例详解
2020/03/26 PHP
js关于精确计算和数值格式化以及直接引js文件
2014/01/28 Javascript
html的DOM中document对象images集合用法实例
2015/01/21 Javascript
javascript中函数作为参数调用的方法
2015/02/09 Javascript
js获取及判断键盘按键的方法
2015/12/01 Javascript
使用requirejs模块化开发多页面一个入口js的使用方式
2017/06/14 Javascript
nodejs实现连接mongodb数据库的方法示例
2018/03/15 NodeJs
vue+express+jwt持久化登录的方法
2019/06/14 Javascript
微信小程序如何实现radio单选框单击打勾和取消
2020/01/21 Javascript
vue中axios防止多次触发终止多次请求的示例代码(防抖)
2020/02/16 Javascript
js实现查询商品案例
2020/07/22 Javascript
[01:21:36]CHAOS vs Alliacne 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
python对url格式解析的方法
2015/05/13 Python
Python同时向控制台和文件输出日志logging的方法
2015/05/26 Python
利用Pandas 创建空的DataFrame方法
2018/04/08 Python
Django REST framework内置路由用法
2019/07/26 Python
详解如何用TensorFlow训练和识别/分类自定义图片
2019/08/05 Python
如何在Anaconda中打开python自带idle
2020/09/21 Python
详解CSS中iconfont的使用
2015/08/04 HTML / CSS
html5本地存储之localstorage 、本地数据库、sessionStorage简单使用示例
2014/05/08 HTML / CSS
工程造价专业大学生自荐信
2013/10/01 职场文书
新学期班主任寄语
2014/01/18 职场文书
汽车装潢店创业计划书范文
2014/02/05 职场文书
大学生简历求职信
2014/06/24 职场文书
大专应届毕业生求职信
2014/07/15 职场文书
竞选班长演讲稿400字
2014/08/22 职场文书
2015年毕业实习工作总结
2015/05/29 职场文书
新学期感想
2015/08/10 职场文书
MySQL 四种连接和多表查询详解
2021/07/16 MySQL
警用民用对讲机找不同
2022/02/18 无线电
一条慢SQL语句引发的改造之路
2022/03/16 MySQL
python 镜像环境搭建总结
2022/09/23 Python