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学习之PHP变量
Oct 09 PHP
php a simple smtp class
Nov 26 PHP
mysql+php分页类(已测)
Mar 31 PHP
探讨:如何使用PhpDocumentor生成文档
Jun 25 PHP
使用Thinkphp框架开发移动端接口
Aug 05 PHP
php实现统计目录文件大小的函数
Dec 25 PHP
php导出生成word的方法
Dec 25 PHP
简单了解将WordPress中的工具栏移到底部的小技巧
Dec 31 PHP
orm获取关联表里的属性值
Apr 17 PHP
PHP大神的十大优良习惯
Sep 14 PHP
PHP实现截取中文字符串不出现?号的解决方法
Dec 29 PHP
laravel-admin自动生成模块,及相关基础配置方法
Oct 08 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路由规则使用示例详解和伪静态功能实现(apache重写)
2014/02/24 PHP
php实现的验证码文件类实例
2015/06/18 PHP
Joomla开启SEF的方法
2016/05/04 PHP
laravel 获取某个查询的查询SQL语句方法
2019/10/12 PHP
不错的新闻标题颜色效果
2006/12/10 Javascript
node+express+jade制作简单网站指南
2014/11/26 Javascript
JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招
2016/03/07 Javascript
javascript之IE版本检测超简单方法
2016/08/20 Javascript
详解react-router如何实现按需加载
2017/06/15 Javascript
React 子组件向父组件传值的方法
2017/07/24 Javascript
vue基于Element构建自定义树的示例代码
2017/09/19 Javascript
Vue 样式绑定的实现方法
2019/01/15 Javascript
vue计算属性无法监听到数组内部变化的解决方案
2019/11/06 Javascript
python自动安装pip
2014/04/24 Python
Python中的推导式使用详解
2015/06/03 Python
简单介绍Python的Django框架加载模版的方式
2015/07/20 Python
使用C#配合ArcGIS Engine进行地理信息系统开发
2016/02/19 Python
python抓取京东小米8手机配置信息
2018/11/13 Python
Python拆分大型CSV文件代码实例
2019/10/07 Python
Win 10下Anaconda虚拟环境的教程
2020/05/18 Python
如何使用Cython对python代码进行加密
2020/07/08 Python
python和node.js生成当前时间戳的示例
2020/09/29 Python
详解Django关于StreamingHttpResponse与FileResponse文件下载的最优方法
2021/01/07 Python
详解HTML5常用的语义化标签
2019/09/27 HTML / CSS
计算 s=(x*y)1/2,用两个宏定义来实现
2016/08/11 面试题
经济管理专业毕业生推荐信
2013/11/11 职场文书
开办加工厂创业计划书
2014/01/03 职场文书
我的小天地教学反思
2014/04/30 职场文书
房屋买卖协议书范本
2014/09/27 职场文书
离婚财产分隔协议书
2014/10/23 职场文书
销售经理工作失职检讨书
2014/10/24 职场文书
2014年党委工作总结
2014/11/22 职场文书
2014年居委会工作总结
2014/12/09 职场文书
选对餐饮营销策略,营业额才会上涨
2019/08/27 职场文书
JavaScript实现复选框全选功能
2021/04/11 Javascript
Vue鼠标滚轮滚动切换路由效果的实现方法
2021/08/04 Vue.js