search for in the  
<OverloadingPatterns>
Last updated: Thu, 19 May 2005

Object Iteration

PHP 5 provides a way for objects to be defined so it is possible to iterate through a list of items, with, for example a foreach statement. By default, all visible properties will be used for the iteration.

Example 19-20. Simple Object Iteration

<?php
class MyClass
{
   public
$var1 = 'value 1';
   public
$var2 = 'value 2';
   public
$var3 = 'value 3';

   protected
$protected = 'protected var';
   private 
$private  = 'private var';

   function
iterateVisible() {
       echo
"MyClass::iterateVisible:\n";
       foreach(
$this as $key => $value) {
           print
"$key => $value\n";
       }
   }
}

$class = new MyClass();

foreach(
$class as $key => $value) {
   print
"$key => $value\n";
}
echo
"\n";


$class->iterateVisible();

?>

The above example will output:

var1 => value 1
var2 => value 2
var3 => value 3

MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var

As the output shows, the foreach iterated through all visible variables that can be accessed. To take it a step further you can implement one of PHP 5's internal interface named Iterator. This allows the object to decide what and how the object will be iterated.

Example 19-21. Object Iteration implementing Iterator

<?php
class MyIterator implements Iterator
{
   private
$var = array();

   public function
__construct($array)
   {
       if (
is_array($array)) {
          
$this->var = $array;
       }
   }

   public function
rewind() {
       echo
"rewinding\n";
      
reset($this->var);
   }

   public function
current() {
      
$var = current($this->var);
       echo
"current: $var\n";
       return
$var;
   }

   public function
key() {
      
$var = key($this->var);
       echo
"key: $var\n";
       return
$var;
   }

   public function
next() {
      
$var = next($this->var);
       echo
"next: $var\n";
       return
$var;
   }

   public function
valid() {
      
$var = $this->current() !== false;
       echo
"valid: {$var}\n";
       return
$var;
   }
}

$values = array(1,2,3);
$it = new MyIterator($values);

foreach (
$it as $a => $b) {
   print
"$a: $b\n";
}
?>

The above example will output:

rewinding
current: 1
valid: 1
current: 1
key: 0
0: 1
next: 2
current: 2
valid: 1
current: 2
key: 1
1: 2
next: 3
current: 3
valid: 1
current: 3
key: 2
2: 3
next:
current:
valid:

You can also define your class so that it doesn't have to define all the Iterator functions by simply implementing the PHP 5 IteratorAggregate interface.

Example 19-22. Object Iteration implementing IteratorAggregate

<?php
class MyCollection implements IteratorAggregate
{
   private
$items = array();
   private
$count = 0;

  
// Required definition of interface IteratorAggregate
  
public function getIterator() {
       return new
MyIterator($this->items);
   }

   public function
add($value) {
      
$this->items[$this->count++] = $value;
   }
}

$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');

foreach (
$coll as $key => $val) {
   echo
"key/value: [$key -> $val]\n\n";
}
?>

The above example will output:

rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]

next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]

next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]

next:
current:
valid:

Note: For more examples of iterators, see the SPL Extension.



User Contributed Notes
Object Iteration
elias at need dot spam
10-Apr-2005 06:15
The MyIterator::valid() method above ist bad, because it
breaks on entries with 0 or empty strings, use key() instead:

<?php
public function valid()
{
   return !
is_null(key($this->var));
}
?>

read about current() drawbacks:
http://php.net/current
strrev('ed.relpmeur@ekneos');
01-Mar-2005 05:25
Use the SPL ArrayAccess interface to call an object as array:

http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html
phpnet at nicecupofteaandasitdown dot com
22-Feb-2005 11:09
You should be prepared for your iterator's current method to be called before its next method is ever called. This certainly happens in a foreach loop. If your means of finding the next item is expensive you might want to use something like this

private $item;
      
function next() {
   $this->item = &$this->getNextItem();
   return $this->item;
}
  
public function current() {
     if(!isset($this->item)) $this->next();
   return $this->item;
}
knj at aider dot dk
18-Dec-2004 10:19
if you in a string define classes that implements IteratorAggregate.
you cant use the default;
<?
...
public function
getIterator() {
       return new
MyIterator($this-><What ever>);
}
..
?>
at least not if you want to use eval(<The string>).
You have to use:
<?
...
public function
getIterator() {
    
$arrayObj=new ArrayObject($this-><What ever>);
     return
$arrayObj->getIterator();
}
...
?>
php at moechofe dot com
13-Dec-2004 06:27
<?php

class MyIterator implements Iterator {

  private
$var = array();

  public function
__construct() {
  
$this->var = array( 1,2,3,4 ); }

  public function
rewind() { reset($this->var); }
  public function
current() { return current($this->var); }
  public function
key() { return key($this->var); }
  public function
next() { return next($this->var); }
  public function
valid() { return $this->current() !== false; }

  }

$it = new MyIterator();

// dont work :(
echo $it[0];

?>

<OverloadingPatterns>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 18:35:34 2005 EDT