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程序?
Dec 08 PHP
PHP OPP机制和模式简介(抽象类、接口和契约式编程)
Jun 09 PHP
PHP的mysqli_query参数MYSQLI_STORE_RESULT和MYSQLI_USE_RESULT的区别
Sep 29 PHP
PHP+jQuery 注册模块开发详解
Oct 14 PHP
php字符比较函数similar_text、strnatcmp与strcasecmp用法分析
Nov 18 PHP
解决php表单重复提交实现方法
Sep 29 PHP
php调用自己java程序的方法详解
May 13 PHP
PHP中explode函数和split函数的区别小结
Aug 24 PHP
基于Codeigniter框架实现的student信息系统站点动态发布功能详解
Mar 23 PHP
PHP实现多图上传和单图上传功能
May 17 PHP
Laravel使用scout集成elasticsearch做全文搜索的实现方法
Nov 30 PHP
解决laravel 表单提交-POST 异常的问题
Oct 15 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 变量定义方法
2009/06/14 PHP
字母顺序颠倒而单词顺序不变的php代码
2010/08/08 PHP
phpmailer中文乱码问题的解决方法
2014/04/22 PHP
php实现粘贴截图并完成上传功能
2015/05/17 PHP
Laravel5.5 实现后台管理登录的方法(自定义用户表登录)
2019/09/30 PHP
JavaScript开发时的五个注意事项
2007/12/08 Javascript
Whatever:hover 无需javascript让IE支持丰富伪类
2010/06/29 Javascript
基于jsTree的无限级树JSON数据的转换代码
2010/07/27 Javascript
jquery 回车事件实现代码
2011/08/23 Javascript
javascript白色简洁计算器
2015/05/04 Javascript
Angular4实现动态添加删除表单输入框功能
2017/08/11 Javascript
vue将对象新增的属性添加到检测序列的方法
2018/02/24 Javascript
JS将网址url转化为JSON格式的方法
2018/07/02 Javascript
详解vue.js移动端配置flexible.js及注意事项
2019/04/10 Javascript
node.js实现http服务器与浏览器之间的内容缓存操作示例
2020/02/11 Javascript
Python 错误和异常小结
2013/10/09 Python
Python3写入文件常用方法实例分析
2015/05/22 Python
Python3实战之爬虫抓取网易云音乐的热门评论
2017/10/09 Python
Python2与python3中 for 循环语句基础与实例分析
2017/11/20 Python
vscode 远程调试python的方法
2017/12/01 Python
python学习之hook钩子的原理和使用
2018/10/25 Python
Python实现定制自动化业务流量报表周报功能【XlsxWriter模块】
2019/03/11 Python
基于Python实现剪切板实时监控方法解析
2019/09/11 Python
Python线程障碍对象Barrier原理详解
2019/12/02 Python
浅谈python 类方法/静态方法
2020/09/18 Python
html5 的a标签 Href 拨电话的写法
2013/11/04 HTML / CSS
西班牙伏林航空公司:Vueling
2016/08/05 全球购物
GLAMGLOW格莱魅美国官网:美国知名的面膜品牌
2016/12/31 全球购物
乌克兰排名第一的在线旅游超市:Farvater.Travel
2020/01/02 全球购物
巴西购物网站:Onofre Agora
2020/06/08 全球购物
举例说明类变量和实例变量的区别
2016/06/30 面试题
生产部统计员岗位职责
2014/01/05 职场文书
工地材料员岗位职责
2015/04/11 职场文书
大学生饮品店创业计划书范文
2019/07/10 职场文书
Mybatis-plus在项目中的简单应用
2021/07/01 Java/Android
Redis 中使用 list,streams,pub/sub 几种方式实现消息队列的问题
2022/03/16 Redis