Using Iterators in PHP

his article shows you how to use the most important iterator classes: ArrayIterator, DirectoryIterator, FilterIterator, and so forth, found in the Standard PHP Library (SPL), and how to integrate SPL with PHP Data Objects (PDO).

The Standard PHP Library

The SPL represents a collection of interfaces and classes for PHP 5 that help resolve some common problems and that let developers take full advantage of object-oriented programming. Some of the SPL’s most used capabilities are: advanced array access, the ability to customize collection iteration with foreach or while, enhanced file and directory access, and advanced SimpleXML object handling. But the best new functionality that the SPL provides comes in the form of iterators.

According to Wikipedia, an iterator is an object that allows a programmer to traverse through all the elements of a collection, regardless of its specific implementation. There are several different types of iterators, each discussed in more detail below.

The ArrayIterator Class

This iterator allows you to modify values and keys while iterating over arrays and objects. You can find documentation for the ArrayIterator methods here.

This first example application iterates recursively over a $numbers array, appends a new value at the end of the array, and finally prints it to the screen:

 'one',    2 => 'two', 3 => 'three',    4 => 'four', 5 => 'five');// Create a new ArrayObject instance$object = new ArrayObject( $numbers );//Create a new RecursiveIteratorIterator instance and pass it to the //RecursiveArrayIterator constructor. $iterator = new RecursiveIteratorIterator( new    RecursiveArrayIterator($object));echo 'Listing the $numbers array recursively:'.'
';//Iterate over the values in the ArrayObjectforeach ($iterator as $key=>$val) echo $key."*****".$val;echo '

';//Append a value at the end of the array using an object$object->append('six');echo 'Listing the $numbers array recursively after '. 'appending a new value:'.'
';//Iterate over the values in the ArrayObjectforeach ($iterator as $key=>$val) echo $key."*****".$val." ";echo '
';?>

The output from the preceding code lists the array twice: once after it is first populated, and again after adding a new value:

Listing the $numbers array recursively:1*****one2*****two3*****three4*****four5*****fiveListing the $numbers array recursively after appending a new value:1*****one 2*****two 3*****three 4*****four 5*****five 6*****six

Here’s a second example that iterates over a $flowers array using the current(), valid(), and next() methods, as described below:

  • valid(): Checks whether the array contains more entries.
  • next(): Moves to the next entry.
  • current(): Returns the current array entry

Finally, the following example lists the number of elements in the $flowers array using the ArrayObject count() method:

';//Iterate over the values in the ArrayObjectfor($iterator = $arrayObj->getIterator();   $iterator->valid();   $iterator->next()){   echo $iterator->key() . ' => ' .       $iterator->current() . '
';}echo '
'.'*******************'.'
';//Counting elementsecho 'The number of elements in the $flowers array is: '. $arrayObj->count().'
';//Seeking a given element$iterator = $arrayObj->getIterator();echo 'Seeking a given value:'.'
';if($iterator->valid()){ $iterator->seek(3); echo $iterator->key() . ' => ' . $iterator->current() . '
'; }?>

The output is:

Sequential list of elements in the $flowers array using getIterator():0 => tulip1 => rose2 => lily3 => snowdrop4 => crocus*******************The number of elements in the $flowers array is: 5Seeking a given value:3 => snowdrop

Listing Classes and Methods with Reflection

As an interesting exercise, you can view a full list of iterator classes and their methods by using the Reflection API, produced by the following short application. Listing 1 shows the output:

The FilterIterator Class

You use this class to filter out unwanted values using the accept() method. The FilterIterator class is not meant to be used directly; instead, you need to extend it to implement custom iterator filters. In particular, you must implement the accept() method.

The following application iterates over the $flowers array, filtering it with the accept() method to list only numeric array key values:

'rose', 'lily',    'b'=>'snowdrop', 'crocus');class FlowerClass extends FilterIterator{   public function __construct( Iterator $iterator ){     parent::__construct( $iterator );   }   //This function checks if the array keys are numeric   function accept(){     return is_numeric($this->key());   }}//Create a new ArrayIterator instance and pass it to the FlowerClass //constructor to create a new FlowerClass object$value = new FlowerClass(new ArrayIterator($flowers));echo 'List all the elements from the $flowers array that    have numeric keys: '.'
';//Iterate over the values in the ArrayIteratorforeach($value as $key=>$value){ echo $key.' =>'.$value.'
';}?>

The output is:

List all the elements from the $flowers array that have numeric keys: 0 =>tulip1 =>lily2 =>crocus

Here’s an alternate version that iterates the $flowers array, listing only the odd array key values:

key() % 2) != 0){         return $this->key();      }   }}//Create a new ArrayIterator instance and //pass it to the MyClass constructor $value = new MyClass(new ArrayIterator($flowers));echo 'List all the $flowers elements with odd numbered keys: '.'
';//Iterate over the $flowers array foreach($value as $key=>$value){ echo $key.' == '.$value.'
';}?>

The output is:

'List all the $flowers elements with odd numbered keys: 1 == rose3 == snowdrop

The DirectoryIterator Class

The DirectoryIterator class provides a simple interface for viewing the contents of filesystem directories. The following example lists the name and size of files in a specific directory:

getFilename() . "
"; // Get size of current DirectoryIterator item echo $file->getSize() . "
"; }?>

Here’s the output:

The filename = iterator_1.phpThe file size = 861The filename = iterator_11.phpThe file size = 484The filename = iterator_2.phpThe file size = 648The filename = iterator_3.phpThe file size = 403

The SimpleXMLIterator Class

The SimpleXMLIterator iterates recursively through all nodes of a SimpleXMLElement object. The examples in this section use the flowers.xml XML document available in the downloadable code, and listed below:

  tulip  rose  crocus  lily  snowdrop

Here’s an example that uses a SimpleXMLIterator to show the first element of the flowers.xml document.

rewind(); //List the current elementvar_dump($xmlIterator->current());?>

The output is:

object(SimpleXMLIterator)#2 (1) { [0]=> string(5) "tulip" }

For the next example, modify the flowers.xml document as follows:

      tulip    snowdrop    rose  crocus  lily

Using this modified version, the next example lists all the child nodes:

rewind(); $xmlIterator->valid();    $xmlIterator->next() ) {   foreach($xmlIterator->getChildren() as $name => $data) {      echo "The children '$data'. ".'
'; }}?>

The output is:

The children 'tulip'. The children 'snowdrop'.

Finally, this next example converts the flowers.xml document into an array, iterates over the array values, and then prints the resulting array:

rewind(); $object->valid(); $object->next() ) {    if(!array_key_exists($object->key(), $xml_array)){      $xml_array[$object->key()] = array();    }    if($object->hasChildren()){      $xml_array[$object->key()][] = ObjectToArray(         $object->current());    }    else{      $xml_array[$object->key()][] = strval($object->current());    }  }  return $xml_array;}// Read flowers.xml and print the results:$XmlToArray = XmlToArray('flowers.xml');print_r($XmlToArray);?>

The output is:

Array ( [flower] => Array ( [0] => Array (    [spring] => Array ( [0] => tulip )    [first] => Array ( [0] => snowdrop ) )    [1] => rose [2] => crocus [3] => lily ) )

SPL and PDO

The PHP Data Objects (PDO) extension gives PHP an interface for accessing databases. The examples in this section use a testphp database containing a users table created using this SQL statement:

create table users    (id int not null auto_increment primary key,    username varchar(50),    email varchar(50),    userpassword varchar(50));

The SQL statements used to populate the bookstore table from Figure 1 are:

INSERT INTO users (id,username,email,userpassword) VALUES     (1,"octavia","[email protected]","pppppp")

 
Figure 1. Table Structure and Content: The figure shows the users table contents and structure from the testphp database.

As an example, the following application connects to the testphp MySQL database using the PDO extension, executes a simple SELECT statement that returns the results as an array, and then iterates over the values:

query('SELECT * from testphp') as $row) {      print_r($row);   }   $dbh = null;} catch (PDOException $e) {   // Executes an SQL statement, returning a result set    // as a PDOStatement    $statement = $dbh->query('SELECT * FROM users');   //Return an array containing all of the result set rows   $result = $ statement ->fetchAll();   //Create an ArrayObject instance   $object = new ArrayObject($result);   //Iterate over the values in the ArrayObject    foreach ($object as $member) {      echo $member->getName() . "
"; } }?>

The output is:

Array ( [id] => 1 [0] => 1 [username] => octavia    [1] => octavia [email] => [email protected]    [2] => [email protected]    [userpassword] => pppppp [3] => pppppp )

In this article, you’ve seen how to implement iterators in your standard applications using the advanced array access, the file and directory access, and the SimpleXML object handling using the Standard PHP Library. Overall, I think you’ll find iterators to be a highly useful addition to your PHP toolset.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

More From DevX