PHP设计模式漫谈之迭代器模式
创始人
2024-06-29 14:21:32
0次

【51CTO独家特稿】今天《PHP设计模式漫谈》系列的主角是迭代器(Iterator)模式,它在一个很常见的过程上提供了一个抽象:位于对象图不明部分的一组对象(或标量)集合上的迭代。迭代有几种不同的具体执行方法:在数组属性,集合对象,数组,甚至一个查询结果集之上迭代。

在对象的世界里,迭代器模式要维持类似数组的功能,看作是一个非侵入性对象刻面(facet),Client类往往分离自真实对象实现,指iterator接口。只要有可能,我们可以给迭代器传送一个引用,代替将来可能发生变化的具体或抽象类。

迭代器模式 
图1 迭代器模式

参与者:

◆客户端(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的内部状态到一个特定的迭代点。#p#

注意,迭代器是比对象集更好的抽象,因为我们可以让InfiniteIterators,NoRewindIterators等,不用与普通数组阵列与一致,因此,Iterator缺少count()函数等功能。
在PHP官方手册中可以找到完整的SPL迭代器列表。得益于对PHP的强力支持,使用迭代器模式的大部分工作都包括在标准实现中,下面的代码示例就利用了标准Iterator和RecursiveIterators的功能。

  1. /**  
  2.  * Collection that wraps a numeric array.  
  3.  * All five public methods are needed to implement  
  4.  * the Iterator interface.  
  5.  */  
  6. class Collection implements Iterator  
  7. {  
  8.     private $_content;  
  9.     private $_index = 0;  
  10.  
  11.     public function __construct(array $content)  
  12.     {  
  13.         $this->_content = $content;  
  14.     }  
  15.  
  16.     public function rewind()  
  17.     {  
  18.         $this->_index = 0;  
  19.     }  
  20.  
  21.     public function valid()  
  22.     {  
  23.         return isset($this->_content[$this->_index]);  
  24.     }  
  25.  
  26.     public function current()  
  27.     {  
  28.         return $this->_content[$this->_index];  
  29.     }  
  30.  
  31.     public function key()  
  32.     {  
  33.         return $this->_index;  
  34.     }  
  35.  
  36.     public function next()  
  37.     {  
  38.         $this->_index++;  
  39.     }  
  40. }  
  41.  
  42. $arrayarray = array('A', 'B', 'C', 'D');  
  43. echo "Collection: ";  
  44. foreach (new Collection($array) as $key => $value) {  
  45.     echo "$key => $value. ";  
  46. }  
  47. echo "\n"; 
  1. /**  
  2.  * Usually IteratorAggregate is the interface to implement.  
  3.  * It has only one method, which must return an Iterator  
  4.  * already defined as another class (e.g. ArrayIterator)  
  5.  * Iterator gives a finer control over the algorithm,  
  6.  * because all the hook points of Iterator' contract  
  7.  * are available for implementation.  
  8.  */  
  9. class NumbersSet implements IteratorAggregate  
  10. {  
  11.     private $_content;  
  12.  
  13.     public function __construct(array $content)  
  14.     {  
  15.         $this->_content = $content;  
  16.     }  
  17.  
  18.     public function contains($number)  
  19.     {  
  20.         return in_array($number, $this->_content);  
  21.     }  
  22.  
  23.     /**  
  24.      * Only this method is necessary to implement IteratorAggregate.  
  25.      * @return Iterator  
  26.      */  
  27.     public function getIterator()  
  28.     {  
  29.         return new ArrayIterator($this->_content);  
  30.     }  
  31. }  
  32.  
  33. echo "NumbersSet: ";  
  34. foreach (new NumbersSet($array) as $key => $value) {  
  35.     echo "$key => $value. ";  
  36. }  
  37. echo "\n"; 
  1. // let's play with RecursiveIterator implementations  
  2. $it = new RecursiveArrayIterator(array(  
  3.     'A',  
  4.     'B',  
  5.     array(  
  6.         'C',  
  7.         'D'  
  8.     ),  
  9.     array(  
  10.         array(  
  11.             'E',  
  12.             'F'  
  13.         ),  
  14.         array(  
  15.             'G',  
  16.             'H',  
  17.             'I'  
  18.         )  
  19.     )  
  20. ));  
  21. // $it is a RecursiveIterator but also an Iterator,  
  22. // so it loops normally over the four elements  
  23. // of the array.  
  24. echo "Foreach over a RecursiveIterator: ";  
  25. foreach ($it as $value) {  
  26.     echo $value;  
  27.     // but RecursiveIterators specify additional  
  28.     // methods to explore children nodes  
  29.     $children = $it->hasChildren() ? '{Yes}' : '{No}';  
  30.     echo $children, ' ';  
  31. }  
  32. echo "\n";  
  33. // we can bridge it to a different contract via  
  34. // a RecursiveIteratorIterator, whose cryptic name  
  35. // should be read as 'an Iterator that spans over  
  36. // a RecursiveIterator'.  
  37. echo "Foreach over a RecursiveIteratorIterator: ";  
  38. foreach (new RecursiveIteratorIterator($it) as $value) {  
  39.     echo $value;  
  40. }  
  41. echo "\n"; 

原文名:Practical Php Patterns: Iterator        作者:Giorgio

原文出处:http://giorgiosironi.blogspot.com/search/label/practical%20php%20patterns

【PHP设计模式系列】

  1. PHP设计模式漫谈之解释器模式
  2. PHP设计模式漫谈之工厂模式
  3. PHP设计模式漫谈之命令模式
  4. PHP设计模式漫谈之结构模式
  5. PHP设计模式漫谈之责任链模式
  6. PHP设计模式漫谈之代理模式

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
如何更省钱? 近期特价热门硒鼓... 如今激光打印设备已经成为商务或企业的绝对主力办公设备,但采购者往往忽视了激光打印设备所用的耗材,相对...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...