The Iterator Pattern: OOP Techniques in PHP

The iterator pattern is one of the most useful, yet unused patterns defined. It provides a way for class users to count and iterate over a set of objects related to the class. This is very useful in MVC (Model-View-Controller) models as they handle data and the logic that pertains to it.

PHP provides two interfaces that already define what you should include in an iterator pattern: Iterator and Countable. Below are their definitions:

Iterator Interface

<?php
interface Iterator implements Traversable
{
    public mixed current();
    public scalar key();
    public void next();
    public void rewind();
    public bool valid();
}
?>

Countable Interface

<?php
interface Countable
{
    public int count();
}
?>

You can already iterate over class properties using the foreach() loop, so the Iterator and Countable interfaces are domain specific — meaning the iteration logic is specific to the functionality of the class.

As an example, let’s assume we have a domain model that manages users (CRUD). We have an additional class that acts as a structure (you don’t have to do this, but it’s easier to read in a blog) for each individual user. You also have a method that retrieves an arbitrary number of users, assigns each to a User class (acting as a struct), and gives back an array. While this is certainly doable, the iterator pattern defines an easier way to process the data.

Example Before Iterator Pattern

<?php
 
class User
{
	public $email;
	public $address;
	public $city;
	public $state;
	public $zip;
}
 
class User_Management
{
	/**
	 * List of users
	 */
	private $users=array();
 
	public function getUserByID($id)
	{
		// go get a user and assign it an instance of User
	}
 
	public function getAllUsers()
	{
		// go get all users, assign each to User class, and add to the self::users array
	}
 
}
 
?>

The above example is pretty typical for domain models without the use of iterator. Adding the iterator, we provide an interface to bi-directionally traverse, get key information and count records.

With the Iterator Pattern Implemented

<?php
 
class User
{
	public $email;
	public $address;
	public $city;
	public $state;
	public $zip;
}
 
class User_Management implements Iterator, Countable
{
	/**
	 * List of users
	 */
	private $users=array();
 
	/**
	 * Position of the iterator
	 */
	private $position=0;
 
	/**
	 * Retrieve the current record
	 */
	public function current()
	{
		return $this->users[$this->position];
	}
 
	/**
	 * Return the current key index
	 */
	public function key()
	{
		return $this->position;
	}
 
	/**
	 * Increment the iterator index
	 */
	public function next()
	{
		++$this->position;
	}
 
	/**
	 * Reset the position
	 */
	public function rewind()
	{
		$this->position = 0;
	}
 
	public function getUserByID($id)
	{
		// go get a user and assign it an instance of User
	}
 
	/**
	 * Validate whether a record at current
	 * position exists
	 */
	public function valid()
	{
		return (isset($this->users[$this->position]));
	}
 
	/**
	 * Return the total number of users
	 */
	public function count()
	{
		return count($this->users);
	}
 
	public function getAllUsers()
	{
		// go get all users, assign each to User class, and add to the self::users array
	}
 
}
 
?>

The domain model now implements Countable and Iterator. The below example shows a couple of uses for this:

<?php
 
$iterator = new User_Management();
foreach ($iterator as $index => $value)
{
	// The $index will contain the current key
	// while the $value will contain the user
	// at the current position
	echo $value->address;
}
// Rewind the iterator
$iterator->rewind();
 
while ($iterator->valid())
{
	$value = $iterator->current();
	echo $value->address;
	$iterator->next();
}
 
// Rewind the iterator
$iterator->rewind();
 
for ($iterator->key(); $iterator->valid(); $iterator->next())
{
	$value = $iterator->current();
	echo $value->address;
}
 
?>

Conclusion
This is a much cleaner, easier approach to iterating over objects. I hope you find this usable in your domain models!

Mega World News Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google Yahoo Buzz StumbleUpon Weekend Joy

TAGS:  , , ,


3 Comments

  1. Thanks for the clear explanation!

  2. No problem! Glad it helped.

  3. [...] to the class. This is very useful in MVC (Model-View-Controller) models as they handle data… [full post] Will Fitch Will Fitch's Blog phptutorialsiteratoroop 0 0 0 [...]

Leave a Reply