Introduction to Iterators in SPL

The Standard PHP Library has a collection of predefined interfaces, by implementing these interfaces your objects sign a “contract” to expose the methods declared in the interface, just like any other interface would, the difference is the PHP engine recognize these interfaces, and have granted additional features for objects implementing them.

One feature is to control the process of how an object is to be iterated over, in PHP5 when iterating over an standard object all public properties are exposed, no other control is given. By implementing the Iterator interface from SPL you will gain “hook” points to control how a object is to be iterated over, another feature can add “syntactic sugar” and make your object callable like an array would, this is done with the ArrayAccess interface.

Iterator

class MailingList implements Iterator
{
	private $_subscribers = null;

	public function __construct()
	{
		# get from database, or some other datasource.
		$this->_subscribers = array(
			'madsleejensen@gmail.com',
			'no-reply@mads-lee.dk',
			'who@no-one.com'
		);
	}

	public function current()
	{
		return current($this->_subscribers);
	}

	public function valid()
	{
		return (current($this->_subscribers) !== false);
	}

	public function next()
	{
		return next($this->_subscribers);
	}

	public function key()
	{
		return key($this->_subscribers);
	}

	public function rewind()
	{
		reset($this->_subscribers);
	}
}

$list = new MailingList();
foreach ($list as $key => $email)
{
	echo $email;
}

IteratorAggregate

Implementing the iterator interface requires quite a lot of methods, sometimes this add unwanted complexity to your class, its possible to delegate the iteration process to another object that implements the Iterator interface. This is done by implementing the IteratorAggregate interface, it defines a single method getIterator() which must return a instanceof Iterator.

class MailingList implements IteratorAggregate
{
	private $_subscribers = null; # an instanceof Iterator.

	public function __construct()
	{
		$dummyData = array(
			'madsleejensen@gmail.com',
			'no-reply@mads-lee.dk',
			'who@no-one.com'
		);

		# wrap the dummy data into a standard
		# implementation of the interface Iterator.
		$this->_subscribers = new ArrayIterator($dummyData);
	}

	public function getIterator()
	{
		return $this->_subscribers;
	}
}

$list = new MailingList();
foreach ($list as $key => $email)
{
	echo $email;
}

The ArrayIterator class, is a standard implementation of  an array iterator which implements the Iterator interface. SPL comes with some “ready to use” implementations for different kind of iterators, which kan ease your work.

If we look at the documentation for ArrayIterator we see that it implements another interface called ArrayAccess, this interface allows you to overload array-like syntax to your object.

ArrayAccess

class User implements ArrayAccess
{
	private $_info = null;

	public function __construct($userId)
	{
		# get user from database, or something.
		$this->_info = array(
			'name' => 'Mads Lee Jensen',
			'email' => 'madsleejensen@gmail.com'
		);
	}

	public function toString()
	{
		return sprintf('My name is %s, mail me on %s',
						$this->_info['name'],
						$this->_info['email']);
	}

	public function offsetSet($key, $value)
	{
		$this->_info[$key] = $value;
	}
	public function offsetGet($key)
	{
		return $this->_info[$key];
	}
	public function offsetExists($key)
	{
		return isset($this->_info[$key]);
	}
	public function offsetUnset($key)
	{
		unset($this->_info[$key]);
	}
}

$mads = new User(1);

echo $mads['name']; # Mads Lee Jensen
echo $mads['email']; # madsleejensen@gmail.com
$mads['name'] = 'Jet Li'; # calls offsetSet('name', 'Jet Li');
$mads['email'] = 'hidden@unknown.com';
# My name is Jet Li, mail me on hidden@unknown.com
echo $mads->toString();

SeekableIterator

The SeekableIterator is a child of the Iterator interface, which means all methods defined in the Iterator interface must be declared when implementing the SeekableIterator, The SeekableIterator add’s a single method seek($position), Standard

iterators will always start from index 0 when iterated over, with seek() your can specify the position from where the iteration should start.

class MailingList implements Iterator
{
	private $_subscribers = null;

	public function __construct()
	{
		# get from database, or some other datasource.
		$this->_subscribers = array(
			'madsleejensen@gmail.com',
			'no-reply@mads-lee.dk',
			'who@no-one.com'
		);
	}

	public function current()
	{
		return current($this->_subscribers);
	}

	public function valid()
	{
		return (current($this->_subscribers) !== false);
	}

	public function next()
	{
		return next($this->_subscribers);
	}

	public function key()
	{
		return key($this->_subscribers);
	}

	public function rewind()
	{
		reset($this->_subscribers);
	}

	public function seek($position)
	{
		if ($position > count($this->_subscribers))
		{
			throw new OutOfBoundsException();
		}

		$this->rewind();

		for ($i = 0; $i < $position; $i++)
		{
			$this->next();
		}
	}
}

$list = new MailingList();
$list->seek(1); # skip to position 1.
while ($list->valid())
{
	echo $list->current();
	$list->next();
}

The final interface i want to introduce in this post, is the Countable, the ArrayIterator class also implements this, this interface declares a single method called count(), The method will be called when the concrete object is passed to the built-in php function count(); ( sizeof() ).

Countable

class Users implements Countable
{
	private $_users = array(
		'Mads',
		'Line',
		'Php',
		'Random'
	);	

	public function count()
	{
		return count($this->_users);
	}
}

$users = new Users();
echo count($users); # returns 4.

Summary

This was a short introduction to some of the SPL interfaces. At first i wanted to write about the more advanced features in SPL but felt it would be better starting with a simple introduction first.

This post is to be followed up by a post about more advanced features of the SPL.

2 Comments
November 20, 2009 in Standard PHP Library
Tagged , , ,

2 Responses

  1. Yo awesome post there. keep it going.I frankly love to browse your post.Last of all have great night

  2. Yo nice blog there. keep it up.I frankly like to read your blog.Last of all have good night

Leave a Reply

Using Gravatars in the comments - get your own and be recognized!

XHTML: These are some of the tags you can use: <a href=""> <b> <blockquote> <code> <em> <i> <strike> <strong>