Objektiteration

PHP 5 bietet eine Möglichkeit, Objekte so zu definieren, dass es möglich ist, eine Liste von Elementen zu durchlaufen, z.B. mit dem foreach Schlüsselwort. Standardmäßig werden alle sichtbaren Eigenschaften für die Iteration benutzt.

Beispiel 19-21. Einfache Objektiteration

<?php
class MyClass
{
    
public $var1 = 'Wert 1';
    
public $var2 = 'Wert 2';
    
public $var3 = 'Wert 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();

?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

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

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

Wie die Ausgabe zeigt, lief das foreach über alle sichtbaren Variablen, auf die zugegriffen werden kann. Um es einen Schritt weiter zu treiben, kann man eines der PHP 5 internen Interfaces, nämlich Iterator, implementieren. Das erlaubt dem Objekt zu entscheiden was und wie das Objekt iteriert wird.

Beispiel 19-22. Objektiteration mit implementiertem Iterator

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

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

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

    
public function current() {
        
$var = current($this->var);
        echo
"aktuell: $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
"nächstes: $var\n";
        return
$var;
    }

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

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

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

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

zurückspulen
aktuell: 1
gültig: 1
aktuell: 1
key: 0
0: 1
nächstes: 2
aktuell: 2
gültig: 1
aktuell: 2
key: 1
1: 2
nächstes: 3
aktuell: 3
gültig: 1
aktuell: 3
key: 2
2: 3
nächstes:
aktuell:
gültig:

Man kann eine Klasse ebenfalls so definieren, dass diese nicht alle Funktionen von Iterator definieren muss, indem man einfach das PHP 5 IteratorAggregate Interface implementiert.

Beispiel 19-23. Objektiteration mit implementiertem IteratorAggregate

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

    
// benötigte Funktion des IteratorAggregate Interface
    
public function getIterator() {
        return new
MyIterator($this->items);
    }

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

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

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

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

zurückspulen
aktuell: Wert 1
gültig: 1
aktuell: Wert 1
key: 0
key/value: [0 -> Wert 1]

nächstes: Wert 2
aktuell: Wert 2
gültig: 1
aktuell: Wert 2
key: 1
key/value: [1 -> Wert 2]

nächstes: Wert 3
aktuell: Wert 3
gültig: 1
aktuell: Wert 3
key: 2
key/value: [2 -> Wert 3]

nächstes:
aktuell:
gültig:

Anmerkung: Für mehr Beispiele für die Benutzung von Iteratoren siehe auch SPL Erweiterung.