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.ini中添加extension=php_mysqli.dll指令的说明
Jun 14 PHP
PHP项目开发中最常用的自定义函数整理
Dec 02 PHP
php excel reader读取excel内容存入数据库实现代码
Dec 06 PHP
php 获取本地IP代码
Jun 23 PHP
php配置php-fpm启动参数及配置详解
Nov 04 PHP
php 使用GD库为页面增加水印示例代码
Mar 24 PHP
PHP fastcgi模式上传大文件(大约有300多K)报错
Sep 28 PHP
php跨服务器访问方法小结
May 12 PHP
php代码架构的八点注意事项
Jan 25 PHP
浅谈mysql_query()函数的返回值问题
Sep 05 PHP
yii2项目实战之restful api授权验证详解
May 20 PHP
在 PHP 和 Laravel 中使用 Traits的方法
Nov 13 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作的文本留言本的例子(一)
2006/10/09 PHP
PHP对称加密算法(DES/AES)类的实现代码
2017/11/14 PHP
PHP 对象接口简单实现方法示例
2020/04/13 PHP
PHP设计模式之 策略模式Strategy详解【对象行为型】
2020/05/01 PHP
用javascript动态调整iframe高度的代码
2007/04/10 Javascript
Google AJAX 搜索 API实现代码
2010/11/17 Javascript
JavaScript 在网页上单击鼠标的地方显示层及关闭层
2012/12/30 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
2015/07/27 Javascript
JavaScript电子时钟倒计时第二款
2016/01/10 Javascript
jQuery Masonry瀑布流插件使用方法详解
2017/01/18 Javascript
jQuery上传多张图片带进度条样式(DEMO)
2017/03/02 Javascript
AngularJS监听路由变化的方法
2017/03/07 Javascript
js实现适配不同的屏幕大小
2017/04/10 Javascript
Vue+Flask实现简单的登录验证跳转的示例代码
2018/01/13 Javascript
js使用文件流下载csv文件的实现方法
2019/07/15 Javascript
解决vue自定义全局消息框组件问题
2019/11/22 Javascript
JavaScript实现PC端四格密码输入框功能
2020/02/19 Javascript
jQuery 图片查看器插件 Viewer.js用法简单示例
2020/04/04 jQuery
vue3为什么要用proxy替代defineProperty
2020/10/19 Javascript
[00:06]Yes,it worked!小卡尔成功穿越时空加入战场!
2019/07/20 DOTA
浅谈flask源码之请求过程
2018/07/26 Python
使用python画社交网络图实例代码
2019/07/10 Python
python反转列表的三种方式解析
2019/11/08 Python
Python 解析简单的XML数据
2020/07/24 Python
html5读取本地文件示例代码
2014/04/22 HTML / CSS
香蕉共和国加拿大官网:Banana Republic加拿大
2018/08/06 全球购物
SmartBuyGlasses比利时:购买品牌太阳镜和眼镜
2019/08/09 全球购物
请介绍一下WSDL的文档结构
2013/03/17 面试题
2014年学习雷锋活动总结
2014/03/01 职场文书
县委党的群众路线教育实践活动工作情况报告
2014/10/25 职场文书
信访维稳工作汇报
2014/10/27 职场文书
小兵张嘎电影观后感
2015/06/03 职场文书
《穷人》教学反思
2016/02/19 职场文书
考生诚信考试承诺书(2016版)
2016/03/25 职场文书
读《庄子》有感:美而不自知
2019/11/06 职场文书
Django实现翻页的示例代码
2021/05/24 Python