class LibraryReleasedExternalIterator { |
SPL 迭代器
《迭代器设计模式和 PHP》中必须论述“标准 PHP 库”(SPL)迭代器。虽然,使用 while 循环结构可以非常紧凑,并且也很有用,但是 PHP 代码或许更适合数组迭代的 foreach 结构。直接在 foreach 循环中使用集合合适吗?这其实就是 SPL 迭代器的目标。(尽管本章整篇都是写 PHP5,下列 SPL 代码只能在 PHP5 中运行,并且仅当在 PHP5 编译中将 SPL 启用。)
Fuecks 写过一篇文章,详细地介绍了 SPL 和 SPL 迭代器;请参阅 http://www.site-
point.com/article/php5-standard-library。使用 SPL 是一种完全不同的实现迭代的方法,因此首先介绍一个新单元测试例子和一个新的类 ForeachableLibrary。 class SplIteratorTestCase extends UnitTestCase { |
ForeachableLibrary 是实现 SPL 迭代器接口的集合。你必须执行 5 个函数来创建 SPL 迭代器:current()、next()、key()、valid() 和 rewind()。 key() 返回集合的当前索引。 rewind() 类似于 reset():在集合启动时重新启动迭代。
class ForeachableLibrary extends Library implements Iterator { protected $valid; function current() { return current($this->collection); } function next() { $this->valid = (false !== next($this->collection)); } function key() { return key($this->collection); } function valid() { return $this->valid; } function rewind() { $this->valid = (false !== reset($this->collection)); } } |
这里,该代码仅仅实现了处理 $collection 属性的必需的函数。(如果你没有实现所有 5 个函数,并且将实现迭代器添加到类 definition,则 PHP 将出现致命错误。)测试尚不成熟,因此,什么都有可能发生。存在一个问题:事实受限于一种迭代类型 - 排序,或者 fil- tering 不可用。可以采取措施来调整这种情况?是的!应用从策略模式中学到的知识(请参阅第 7 章),将 SPL 迭代器的 5 个函数作为另一个对象的示例。这是关于 PolymorphicForeachableLibrary 的测试。
class PolySplIteratorTestCase extends UnitTestCase { protected $lib; function setup() { $this->lib = new PolymorphicForeachableLibrary; $this->lib->add(new Media(‘name1’, 2000)); $this->lib->add(new Media(‘name2’, 2002)); $this->lib->add(new Media(‘name3’, 2001)); } function TestForeach() { $output = ‘’; foreach($this->lib as $item) { $output .= $item->name; } $this->assertEqual(‘name1name2name3’, $output); } } |
这种情况与 SplIteratorTestCase 测试的唯一差别在于 $this->lib 属性类是在 setUp() 方法中创建的。这意味着:这两个类的运行方式必须一致。PolymorphicForeachableLibrary:class PolymorphicForeachableLibrary扩展库
implements Iterator { |
class StandardLibraryIterator { protected $valid; protected $collection; function __construct($collection) { $this->collection = $collection; } function current() { return current($this->collection); } function next() { $this->valid = (false !== next($this->collection)); } function key() { return key($this->collection); } function valid() { return $this->valid; |
测试类
现在,代码更加复杂了,但是其如何支持其它迭代器类型?添加一个关于“发行版”迭代器的测试,来查看这种设计的其它迭代器如何工作。
class PolySplIteratorTestCase extends UnitTestCase { |
使用了 foreach 控制结构进行循环。
class PolymorphicForeachableLibrary |
class ReleasedLibraryIterator extends StandardLibraryIterator { function __construct($collection) { usort($collection ,create_function(‘$a,$b’,’return ($a->year - $b->year);’)); $this->collection = $collection; } } |
你可以简单地通过扩展 StandardLibraryIterator 并覆盖构造函数来添加入局数组的排序,从而实现 ReleasedLibraryIterator。并且,通过它,你可以有一个 working PolymorphicForeachableLibrary。
总结
迭代器是标准化地地处理应用程序中对象集合的方法。这些例子是基于数组的,但是对于拥有同一个接口的非数组集合,工作起来将更加强大。使用 foreach 控制结构方式的集合确实非常酷。 SPL 实现中最不幸的问题是与迭代器可能存在的名称空间冲突。有多少 PHP4 面向对象的代码拥有类似于迭代器类作为库迭代器类的基类?在一些容量中有多少 5 种必需方法的定义?可能一个更加具有深刻含义的名称就能实现 Foreachable。如果你选择使用 SPL,则还应该研究其它支持的迭代器,例如RecursiveArrayIterator 和其它众多迭代器。