This article, the first of two parts, explains how to use the Iteratorpattern to manipulate any collection of objects. It is excerpted fromchapter eight of the book PHP|architect's Guide to PHP Design Patterns, written by Jason E. Sweat (PHP|architect, 2005; ISBN: 0973589825).
OBJECT-ORIENTEDPROGRAMMING ENCAPSULATES application logic in classes. Classes, inturn, are instantiated as objects, and each individual object has adistinct identity and state. Individual objects are a useful way toorganize your code, but often you want to work with a group of objects, or a collection. A set of rows from a SQL query is a collection, as is the list of Property objects in the Monopoly game examples shown earlier in the book.
A collection need not be homogeneous either. A Window object in a graphical user interface framework could collect any number of control objects—a Menu, a Slider, and a Button,among others. Moreover, the implementation of a collection can vary: aPHP array is a collection, but so is a hash table, a linked list, astack, and a queue.
The Problem
How can one easily manipulate any collection of objects?
The Solution
Use the Iterator pattern to provide uniform access to the contents of a collection.
You may not realize it, but you use the Iterator pattern every day—it's embodied in PHP's array typeand rich set of array manipulation functions. (Indeed, given thecombination of the native array type in the language and a host offlexible functions designed to work with this native type, you need apretty compelling reason not to use arrays as your means ofmanipulating collections of objects.)
The reset() function restarts iteration to the beginning of the array; current() returns the value of the current element; and next() advances to the next element in the array and returns the new current()value. When you advance past the end of the array, next() returns false. Using these iteration methods, the internal implementation of a PHP array is irrelevant to you.
Iterator couples the object-oriented programming principles of encapsulation and polymorphism. Using Iterator,you can manipulate the objects in a collection without explicitlyknowing how the collection is implemented or what the collectioncontains (what kinds of objects). Iterator provides a uniforminterface to different concrete iteration implementations, which docontain the details of how to manipulate a specific collection,including which items to show (filtering) and in what order (sorting).
Let's create a simple object to manipulate in a collection. (Though this example is in PHP5, Iterators arenot unique to PHP5 and most of the examples in this chapter work inPHP4 as well, albeit with a healthy amount of reference operatorsadded). The object, Lendable, representsmedia such as movies and albums and is intended to be part of a website or service to let users review or lend portions of their mediacollection to other users. (For this example, do not concern yourselfwith persistence and the like.)
Let's start with the following test as a basis for the design of Lendable.
// PHP5 class LendableTestCase extends UnitTestCase { function TestCheckout() { $item = new Lendable; $this->assertFalse($item->borrower); $item->checkout('John'); $this->assertEqual('borrowed', $item->status); $this->assertEqual('John', $item->borrower); } function TestCheckin() { $item = new Lendable; $item->checkout('John'); $item->checkin(); $this->assertEqual('library', $item->status); $this->assertFalse($item->borrower); } }
To implement the requirements of this initial test, let's create aclass with a few public attributes and some methods to toggle thevalues of these attributes:
class Lendable { public $status = 'library'; public $borrower = ''; public function checkout($borrower) { $this->status = 'borrowed'; $this->borrower = $borrower; } public function checkin() { $this->status = 'library'; $this->borrower = ''; } }