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 相关文章推荐
php,ajax实现分页
Mar 27 PHP
PHP Array交叉表实现代码
Aug 05 PHP
PHP 图片上传代码
Sep 13 PHP
如何利用php array_multisort函数 对数据库结果进行复杂排序
Jun 08 PHP
PHP输出英文时间日期的安全方法(RFC 1123格式)
Jun 13 PHP
PHP把JPEG图片转换成Progressive JPEG的方法
Jun 30 PHP
PHP内置的Math函数效率测试
Dec 01 PHP
php根据指定位置和长度获得子字符串的方法
Mar 17 PHP
php上传图片客户端和服务器端实现方法
Mar 30 PHP
thinkPHP框架实现的简单计算器示例
Dec 07 PHP
laravel-admin 实现在指定的相册下添加照片
Oct 21 PHP
TP5框架实现一次选择多张图片并预览的方法示例
Apr 04 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
PHP+memcache实现消息队列案例分享
2014/05/21 PHP
php抓取网站图片并保存的实现方法
2015/10/29 PHP
thinkPHP使用post方式查询时分页失效的解决方法
2015/12/09 PHP
JavaScript 高级篇之DOM文档,简单封装及调用、动态添加、删除样式(六)
2012/04/07 Javascript
Enter转换为Tab的小例子(兼容IE,Firefox)
2013/11/14 Javascript
基于jquery实现的文字向上跑动类似跑马灯的效果
2014/06/17 Javascript
javascript中Date对象的getDay方法使用指南
2014/12/22 Javascript
JavaScript实现添加及删除事件的方法小结
2015/08/04 Javascript
js图片卷帘门导航菜单特效代码分享
2015/09/10 Javascript
JS中检测数据类型的几种方式及优缺点小结
2016/12/12 Javascript
AngularJS指令与指令之间的交互功能示例
2016/12/14 Javascript
js中创建对象的几种方式
2017/02/05 Javascript
ES6新特性七:数组的扩充详解
2017/04/21 Javascript
jQuery实现的简单动态添加、删除表格功能示例
2017/09/21 jQuery
详解使用Typescript开发node.js项目(简单的环境配置)
2017/10/09 Javascript
JavaScript伪数组用法实例分析
2017/12/22 Javascript
Vue+ElementUI实现表单动态渲染、可视化配置的方法
2018/03/07 Javascript
javascript中contains是否包含功能实现代码(扩展字符、数组、dom)
2020/04/07 Javascript
js实现简单的无缝轮播效果
2020/09/05 Javascript
原生js中运算符及流程控制示例详解
2021/01/05 Javascript
python字典基本操作实例分析
2015/07/11 Python
详解 Python 读写XML文件的实例
2017/08/02 Python
Python2随机数列生成器简单实例
2017/09/04 Python
Python处理命令行参数模块optpars用法实例分析
2018/05/31 Python
Python+selenium 获取浏览器窗口坐标、句柄的方法
2018/10/14 Python
Django渲染Markdown文章目录的方法示例
2019/01/02 Python
使用k8s部署Django项目的方法步骤
2019/01/14 Python
Python用字典构建多级菜单功能
2019/07/11 Python
python实现输出一个序列的所有子序列示例
2019/11/18 Python
tensorflow查看ckpt各节点名称实例
2020/01/21 Python
使用python从三个角度解决josephus问题的方法
2020/03/27 Python
python能做哪些生活有趣的事情
2020/09/09 Python
python使用dlib进行人脸检测和关键点的示例
2020/12/05 Python
计算机专业自荐信
2013/10/14 职场文书
MySQL 发生同步延迟时Seconds_Behind_Master还为0的原因
2021/06/21 MySQL
Python内置类型集合set和frozenset的使用详解
2022/04/26 Python