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 相关文章推荐
利用文件属性结合Session实现在线人数统计
Oct 09 PHP
用PHP实现多服务器共享SESSION数据的方法
Mar 16 PHP
简单的方法让你的后台登录更加安全(php中加session验证)
Aug 22 PHP
用来解析.htpasswd文件的PHP类
Sep 05 PHP
PHP 动态生成静态HTML页面示例代码
Jan 15 PHP
PHP保存带BOM文件的方法
Feb 12 PHP
php实现网页缓存的工具类分享
Jul 14 PHP
PHP获取当前URL路径的处理方法(适用于多条件筛选列表)
Feb 10 PHP
PHP单例模式与工厂模式详解
Aug 29 PHP
PHP实现数组的笛卡尔积运算示例
Dec 15 PHP
PHP微商城开源代码实例
Mar 27 PHP
Laravel框架实现定时Task Scheduling例子
Oct 22 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
ThinkPHP中的关联模型注意点
2014/06/16 PHP
php简单日历函数
2015/10/28 PHP
php实现socket推送技术的示例
2017/12/20 PHP
Aster vs Newbee BO3 第三场2.18
2021/03/10 DOTA
Javascript 学习笔记 错误处理
2009/07/30 Javascript
jquery form 隐藏的input 选择
2014/04/29 Javascript
网站接入QQ登录的两种方法
2014/07/22 Javascript
详解JavaScript的策略模式编程
2015/06/24 Javascript
Angularjs实现多个页面共享数据的方式
2016/03/29 Javascript
微信小程序利用co处理异步流程的方法教程
2017/05/20 Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
2017/07/07 Javascript
解决Vue 项目打包后favicon无法正常显示的问题
2018/09/01 Javascript
three.js着色器材质的内置变量示例详解
2020/08/16 Javascript
python模拟登陆Tom邮箱示例分享
2014/01/13 Python
Python中将dataframe转换为字典的实例
2018/04/13 Python
python 获取当天凌晨零点的时间戳方法
2018/05/22 Python
Python读取excel中的图片完美解决方法
2018/07/27 Python
Python列表list操作相关知识小结
2020/01/29 Python
Python IDE环境之 新版Pycharm安装详细教程
2020/03/05 Python
Python内置方法和属性应用:反射和单例(推荐)
2020/06/19 Python
利用css3画个同心圆示例代码
2017/07/03 HTML / CSS
基于html5实现的图片墙效果
2014/10/16 HTML / CSS
Hotels.com爱尔兰:全球酒店预订
2017/02/24 全球购物
6号汽车旅馆预订:Motel 6
2018/02/11 全球购物
电子商务专业个人的自我评价分享
2013/10/29 职场文书
小学母亲节活动方案
2014/03/14 职场文书
教师批评与自我批评总结
2014/10/16 职场文书
高中生毕业评语
2014/12/30 职场文书
小学教师节活动总结
2015/03/20 职场文书
社会实践活动总结格式
2015/05/11 职场文书
校运会加油稿大全
2015/07/22 职场文书
php引用传递
2021/04/01 PHP
python-opencv 中值滤波{cv2.medianBlur(src, ksize)}的用法
2021/06/05 Python
Go语言基础map用法及示例详解
2021/11/17 Golang
解决vue中provide inject的响应式监听
2022/04/19 Vue.js
基于Python编写一个监控CPU的应用系统
2022/06/25 Python