PHP Iterator

Das Iterator-Interface ermöglicht, dass man über ein Objekt mittels des foreach-Konstrukt iterieren kann und sich dabei in der Art verhält als ob es ein Array sei. Für die Implementierung der Schnittstelle werden fünf Methoden benötigt:

rewind()

Zurücksetzen der aktuellen Cursorposition auf das erste Element.

current()

Liefert das Element in der aktuellen Position

key()

Liefert die Positionsnummer/Schlüssel zum aktuellen Element

Sie wird im Rahmen folgender Iteration abgerufen:

foreach( $iterator as $key => $value )
{
}

Diese Methode wird nicht aufgerufen wenn durch das foreach-Konstrukt kein Schlüssel abverlangt wird:

foreach( $iterator as $value )
{
}

next()

Springt zum nächsten Element

valid()

Prüft ob die aktuelle Position ein Element beinhaltet.


Simples Beispiel

Nachfolgend ein einfaches Beispiel welches ein internes Array im Objekt nach Außen verbindet.

class MyIterator implements Iterator
{
    private $pos;
    private $data = array();

    public function __construct( array $data )
    {
        $this->data = $data;
    }
    public function rewind()
    {
        $pos = 0;
    }

    public function current()
    {
        return $this->data[$pos];
    }

    public function key()
    {
        return $pos;
    }

    public function next()
    {
        $pos++;
    }

    public function valid()
    {
        return array_key_exists( $this->data, $pos );
    }
 }

Abrufreihenfolge

Es ist wichtig zu verstehen in welcher Reihenfolge in dem Eingangs erwähnten foreach()-Beispiel die jeweiligen Methoden abgerufen werden um diese sodann auch richtig zu implementieren.

Dafür habe ich nachfolgendes Schaubild skizziert welches den Abruf der jeweiligen Methoden in der Iteration darstellt:

SAM_9205

Beispiel einer Iteration:

$data = array( 'Äpfel', 'Bananen', 'Birnen', 'Pfaumen' );
$iterator = new MyIterator( $data );

foreach( $iterator as $fruit )
{
    echo $fruit . PHP_EOL;
}

Man ist nun in der Lage zusätzliche Aktionen bei der Datenverarbeitung vorzunehmen oder andere Datenquellen zu erschließen.

Komplexes Beispiel

So kann zum Beispiel auch eine CSV-Datei sequentiell eingelesen und verarbeitet werden als sei diese ein Array. Für einen CSV-Iterator kann man nun folgende Implementierung vornehmen:

class CsvIterator implements Iterator
{
  private $delimeter = ',';
  private $skip_first = true;
  private $row;
  private $current = array();
  private function read() {

    $eof = feof( $this->file_handle );
    $this->current = false;

    if( !$eof ) {
      do
      {
       $this->current = fgetcsv( $this->file_handle, null, $this->delimiter );
        if( $this->current === false ) {
          break;
        }
        $this->row++;
      } while( $this->row <= 1 && $this->skip_first );
    }

    return !$eof && $this->current !== false;
  }

  public function rewind() {

    $this->row = 0;
    rewind( $this->file_handle );
    $this->read();
  }

  public function valid() {

    return !empty( $this->current );
  }

  public function current() {

    return $this->current;
  }

  public function key() {

    return $this->row;
  }

  public function next() {

    return $this->read();
  }

Veröffentlicht von

Sebastian

Als erfahrener Softwarentwickler entwickelt Sebastian in einer Softwareschmiede in Bonn Individualsoftware mit den Schwerpunkten in PHP und MySQL. Er hat eine pfiffige Frau sowie drei quirlige Söhne, fährt gerne Auto und liebt handwerkliche Arbeiten die im häuslichen Umfeld so anfallen.