No chapter on the Iterator design pattern and PHP would be complete without discussing the "Standard PHP Library" (SPL) iterator. The while loop structure used so far is very compact and usable, but PHP coders may be more comfortable with the foreach structure for array iteration. Wouldn't it be nice to use a collection directly in a foreach loop? That's exactly what the SPL iterator is for. (Even though this chapter has been written entirely for PHP5, the following SPL code is the only code that works solely in PHP5, and then only if you've compiled PHP 5 with SPL enabled.) Harry Fuecks wrote a nice article introducing the SPL and covering the SPL iterator; see http://www.sitepoint.com/article/php5-standard-library. Using SPL is essentially a completely different way to implement iteration, so let's start over with a new unit test case and a new class, the ForeachableLibrary. class SplIteratorTestCase extends UnitTestCase { ForeachableLibrary is the collection that implements the SPL Iterator interface. You have to implement five functions to create an SPL iterator: current(), next(), key(), valid(), and rewind(). key() returns the current index of your collection. rewind() is like reset(): iteration restarts at the start of your collection. class ForeachableLibrary Here, the code we just implements the required functions working on the $collection attribute. (If you don't implement all five functions and you add the implements Iterator to your class definition, PHP will generate a fatal error.) The tests are "green," so everything is happy. There's just one problem: the implementation is limited to one style of iteration—sorting or filtering is impossible. Can anything be done to rectify this? Yes! Apply what you learned from the Strategy pattern (see Chapter 7) and delegate the SPL iterator's five functions to another object. This is a test for PolymorphicForeachableLibrary. class PolySplIteratorTestCase extends UnitTestCase { The only difference between this case and the test for SplIteratorTestCase is the class of the Here's PolymorphicForeachableLibrary. class PolymorphicForeachableLibrary Library is extended to get the collection manipulation methods. The SPL methods are added, too, all delegating to the $iterator attribute, which is created in rewind(). Below is the code for the StandardLibraryIterator. class StandardLibraryIterator { This code should look familiar: essentially, it's a copy of the five SPL functions from the ForeachableLibrary class. The tests pass. OK, the code is more complex now, but how does it support additional iterator types? Let's add a test for a "released" version of the iterator to see how additional iterator types work in this design. class PolySplIteratorTestCase extends UnitTestCase { This test case above should look familiar, too, as it's very similar to the previous "release" iterator, but using the foreach control structure to loop. class PolymorphicForeachableLibrary The new iteratorType() method lets you switch which style of iterator you want to use. (Since the iterator type isn't chosen during the instantiation of the object and because you can choose a different iterator type on-the-fly by calling the iteratorType() method again, the code is actually implementing the State pattern, rather than the Strategy pattern.) class ReleasedLibraryIterator You can easily implement ReleasedLibraryIterator by extending StandardLibraryIterator and overriding the constructor to add the sorting of the incoming array. And with that you have a working PolymorphicForeachableLibrary.
blog comments powered by Disqus |
|
|
|
|
|
|
|