Simple Object Iterators in PHP

Contributing Editor

If you’ve been coding in PHP for a while, you may be familiar with the foreach loop. It provides an easy way to analyze every item in an array, e.g.


$myArray = array();
$myArray[] = "First item";
$myArray[] = "Second item";
$myArray[] = "Third item";

foreach ($myArray as $i) {
	echo "<p>$i</p>";
}

As well as arrays, it’s also possible loop through an object. If your object contains a collection of items, you can use a foreach loop to iterate over each of them. It doesn’t matter what’s in that collection or how it’s retrieved, e.g.

  • records from a database
  • navigation links
  • names of files within a directory
  • lines of text read from a file
  • product objects in a specific shop category

Iterators is a subject which strikes fear into the heart of many developers. They sound complex and are often explained with indecipherable abstract references. They’re best explained with a simple example so we’ll create a basic class which defines a list of web technologies:


class WebTechnologies
{
	private $tech;

	// constructor
	public function __construct() {
		$this->tech = explode( ',', 'PHP,HTML,XHTML,CSS,JavaScript,XML,XSLT,ASP,C#,Ruby,Python') ;
	}

}

The private $tech array cannot be accessed outside of the class. You could make it public or return its contents, but iterators provide a more elegant alternative.

Assuming you already have the data in an array, the quickest way to make an object traversable is to implement the IteratorAggregate interface:


class WebTechnologies implements IteratorAggregate
{...

To complete the code, we must then define a public getIterator() function within our class. This must return something which can be iterated — such an ArrayIterator object with our $tech array passed to its constructor:


// return iterator
public function getIterator() {
	return new ArrayIterator( $this->tech );
}

We can now iterate over all items within the $tech array. The full code:


class WebTechnologies implements IteratorAggregate
{

	private $tech;

	// constructor
	public function __construct() {
		$this->tech = explode( ',', 'PHP,HTML,XHTML,CSS,JavaScript,XML,XSLT,ASP,C#,Ruby,Python' );
	}
	
	// return iterator
	public function getIterator() {
		return new ArrayIterator( $this->tech );
    }

}

// create object
$wt = new WebTechnologies();

// iterate over collection
foreach ($wt as $n => $t) {
	echo "<p>Technology $n: $t</p>";
}

Great. But what if our object’s collection isn’t an array? In that situation, we require more sophisticated iterators … watch out for a full tutorial coming soon.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • amit

    Seems to be a problem in your final code above. Line #15, foreach is commented out, eh! ;)

    Also, you created an object of WebTechnologies class in $wt & then you are iterating over $wt but I doubt that will work as the constructor neither returns anything nor calls the getIterator() function which returns the ArrayIterator object.

    Also, I’m kind of missing the point of this much code (would appreciate an explanation) as when you explode the string in the constructor, the array can be iterated over in a loop.. To make that private array accessible, you can just write a getter function or make that array public.

    • Mal Curtis

      Amit, ignore the commented out line – that looks like a typo. What’s happening here is that by using $wt in the foreach loop, PHP is automatically calling the getIterator method to retrieve the array that it should be iterating through. $wt is just an instance of the WebTechnologies class, but since it implements IteratorAggregate you’re able to use it in a foreach loop.

    • Wallie

      You should use this to keep the class members encapsulated because if you make the array public you can modify it without the class knowing about it. If (for example) you have an array which may only contain numbers, and you make it public then someone else may come along and accidentally insert a string value into it, which could break you internal class logic.

  • Jason

    You can iterate over an objects public fields by default, so what is the point of this?

    • http://www.optimalworks.net/ Craig Buckler

      This object doesn’t have any public properties — and you may not want or need any. Essentially, iterators give you control over what is returned in each step of a foreach loop.

      This example is a little limited since you already have an array (which could be retrieved via a getter or exposed as a public property). However, you could use the iterator to return modified data, e.g. $tech sorted into alphabetic order.

      • David

        Or only iterate over elements that fit a certain criteria (FilterIterator), prefetch the next element (CachingIterator), iterate over several iterators (MultipleIterator), iterate through a multidimensional structure (RecursiveIterator), etc.

  • Stormrider

    “Also, you created an object of WebTechnologies class in $wt & then you are iterating over $wt but I doubt that will work as the constructor neither returns anything nor calls the getIterator() function which returns the ArrayIterator object.”

    The getIterator method is called automatically when you attempt to iterate around the object, as happens with all classes that implement the IteratorAggregate Interface.

    Constructors cannot return anything, since they automatically return the object created by the construction!

    • Stewart R

      But surely it’s good practise to use $wt->getIterator() in the foreach rather than assuming anyone reading your code would be able to understand whats going on rather than just passing the object and assuming they know the “magic” inner workings of the code?

      • Stormrider

        No, all you need to know is that you can iterate over it. The getIterator method is automatically called by the very fact that you are iterating over it. Keeping the internal workings of the class hidden is a bonus here – you don’t need or want to get involved with the inner workings of the class, you just want to be able to use it. It’s good to know you can iterate over an object without having to be involved with the workings!

  • Steve G

    amit – The constructor is setting the private var to an array via the explode, a return in a constructor returns the object. No return is required.

    As for nothing calling the getIterator() method, this is done by some magic in the foreach that notices the object extends an iterator interface.

    Least thats how I understand anyway.

  • http://www.optimalworks.net/ Craig Buckler

    There was a missing carriage return following “// iterate over collection” which I’ve put back. It seems WordPress decided that my code wasn’t good enough!

  • Tali Luvhengo

    Bookmark :)