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的cms
Dec 19 PHP
Windows下利用Gvim写PHP产生中文乱码问题解决方法
Apr 20 PHP
php 文章调用类代码
Aug 11 PHP
洪恩在线成语词典小偷程序php版
Apr 20 PHP
php字符串截取的简单方法
Jul 04 PHP
PHP生成图片验证码、点击切换实例
Jun 25 PHP
Thinkphp中的curd应用实用要点
Jan 04 PHP
php操作(删除,提取,增加)zip文件方法详解
Mar 12 PHP
php获取Google机器人访问足迹的方法
Apr 15 PHP
php基础教程
Aug 26 PHP
利用Laravel生成Gravatar头像地址的优雅方法
Dec 30 PHP
ThinkPHP5.1框架页面跳转及修改跳转页面模版示例
May 06 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发送html格式文本邮件的方法
2015/06/10 PHP
thinkphp分页集成实例
2017/07/24 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
Laravel框架Eloquent ORM简介、模型建立及查询数据操作详解
2019/12/04 PHP
浅析PHP反序列化中过滤函数使用不当导致的对象注入问题
2020/02/15 PHP
7个Javascript地图脚本整理
2009/10/20 Javascript
JavaScript 学习笔记(十四) 正则表达式
2010/01/22 Javascript
div层的移动及性能优化
2010/11/16 Javascript
深入理解javascript动态插入技术
2013/11/12 Javascript
JavaScript按位运算符的应用简析
2014/02/04 Javascript
Flexigrid在IE下不显示数据的有效处理方法
2014/09/04 Javascript
前端程序员必须知道的高性能Javascript知识
2016/08/24 Javascript
Angular2 (RC4) 路由与导航详解
2016/09/21 Javascript
node.js中的事件处理机制详解
2016/11/26 Javascript
微信小程序 template模板详解及实例代码
2017/03/09 Javascript
jquery mobile实现可折叠的导航按钮
2017/03/11 Javascript
ionic使用angularjs表单验证(模板验证)
2018/12/12 Javascript
Vue的自定义组件不能使用click方法的解决
2020/07/28 Javascript
详解三种方式在React中解决绑定this的作用域问题并传参
2020/08/18 Javascript
[03:37]2015国际邀请赛第四日现场精彩集锦
2015/08/08 DOTA
Python实现的寻找前5个默尼森数算法示例
2018/03/25 Python
python操作excel的包(openpyxl、xlsxwriter)
2018/06/11 Python
pyqt5 键盘监听按下enter 就登陆的实例
2019/06/25 Python
python开启debug模式的方法
2019/06/27 Python
Python OpenCV 使用滑动条来调整函数参数的方法
2019/07/08 Python
Django models文件模型变更错误解决
2020/05/11 Python
python3.7.3版本和django2.2.3版本是否可以兼容
2020/09/01 Python
python zip()函数的使用示例
2020/09/23 Python
python 使用csv模块读写csv格式文件的示例
2020/12/02 Python
mysql的最长数据库名,表名,字段名可以是多长
2014/04/21 面试题
面向对象编程的优势是什么
2015/12/17 面试题
报关报检委托书
2014/04/08 职场文书
党员教师自我剖析材料
2014/09/29 职场文书
施工单位工程部经理岗位职责
2015/04/09 职场文书
2015年信息中心工作总结
2015/05/25 职场文书
Java实现给Word文件添加文字水印
2022/02/15 Java/Android