Computerworld

PHP 5: New iterations

An iterator is a mechanism by which you can traverse the values in some programmatic construct, the most basic being the for() and while() loops. The concept behind these constructs does not map directly to objects, however, as they store a variety of different types of data which may need to be traversed in a user-defined way. The problem is defining what you're iterating through: properties and methods. In PHP 5, the programmer can define (or 'overload') this behaviour.

Python vs. PHP: Choosing your next project's language

The most basic case is where we just want to output public methods. This is the default behaviour, as shown:


01 <?
02 class Test {
03 public $x = 1;
04 private $y = 2;
05
06 function pri()
07 {
08 echo "Test";
09 }
10 }
11
12 $obj = new Test;
13 foreach ($obj as $key => $val) {
14 echo "$key = $val\n";
15 }
16 ?>


This outputs 'x = 1'. It ignores the private member $y and the method pri().

So, how do we define our own iteration behaviour? First, we must tell the PHP interpreter that our class defines its own iterator, and, second, we must implement the functions used to perform the iteration: rewind(), which resets the iterator; next(), which increments the iterator; key(), which returns the current key; current(), which returns the current value; and valid(), which is used to determine whether iteration should continue.

The following example iterates through all methods in the class newTest.


01 <?
02 class newTest implements Iterator {
03 	private $methods;
04 	private $i;
05 	function __construct() {
06 		$this->methods = get_class_methods($this);
07 	}
08 	function pri1()	{
09 		echo "pri1\n";
10 	}
11 	function pri2() {
12 		echo "pri2\n";
13 	}
14 	function rewind() {
15 		$this->i = 0;
16 	}
17 	function valid() {
18 		return $this->i < count($this->methods);

19 } 20 function key() { 21 return $this->i; 22 } 23 function current() { 24 return $this->methods[$this->i]; 25 } 26 function next() { 27 $this->i++; 28 } 29 } 30 $obj = new newTest; 31 foreach($obj as $key => $val) { 32 echo "$key = $val\n"; 33 } 34 ?>



On line 02 we define the class newTest. The keyword 'implements' tells PHP that the following class implements a particular programmatic construct and that it can be used in certain ways. In this case, we are implementing 'Iterator'.

On lines 03 and 04 we define two private properties: $methods and $i. $methods will be the list of methods and $i is an internal counter. On line 05, we define a construct which is run when the object is instantiated. This stores an array of the methods in the current class in $methods. We then define a few basic methods pri1() and pri2().

Beginning on line 14, we define the methods needed to implement the iterator. The method rewind() resets the internal counter $i. valid() checks that the internal counter is less than the number members of $methods. key() returns the position of the internal counter, and current() provides the current member in $methods. Finally, next() increments $i.

On line 30, we instantiate the class calling foreach() on line 31 to iterate through the methods. The output is as follows:


0 =
01 = pri1
02 = pri2
03 = rewind
04 = valid
05 = key
06 = current
07 = next


The first line of the output has an empty value string because the first method in newTest is __construct, the constructor of the class and PHP 5 is not aware of the method name when it constructs newTest. The output after this consists of the other methods in the class including those which implement the iterator.

You may not want to include the methods which implement the iterator in this list, however. To include only the 'user' level methods in this list you would change line 06 to:


$methods = array("pri1", "pri2");


Next month we will continue to look at PHP 5, including the introduction of exceptions.