<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ebene7 &#187; Iterator</title>
	<atom:link href="http://blog.ebene7.com/schlagwort/iterator/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ebene7.com</link>
	<description></description>
	<lastBuildDate>Tue, 04 Jun 2013 18:57:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>&#8220;Walkable&#8221; Iterator</title>
		<link>http://blog.ebene7.com/2012/07/31/walkable-iterator/</link>
		<comments>http://blog.ebene7.com/2012/07/31/walkable-iterator/#comments</comments>
		<pubDate>Tue, 31 Jul 2012 04:00:00 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Array]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[each]]></category>
		<category><![CDATA[Foreach]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[Schleife]]></category>
		<category><![CDATA[Visitor Pattern]]></category>
		<category><![CDATA[walk]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3499</guid>
		<description><![CDATA[In PHP haben Entwickler seit Version 5 die Möglichkeit, den Zugriff auf Datenstrukturen durch eigene oder bereits in der SPL vorhandene Iteratoren zu kontrollieren. Das ist einfach und hat sicherlich auch schon jeder einmal gemacht. Damit ist dann zumindest der &#8230; <a href="http://blog.ebene7.com/2012/07/31/walkable-iterator/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In PHP haben Entwickler seit Version 5 die Möglichkeit, den Zugriff auf Datenstrukturen durch eigene oder bereits in der <a href="http://www.php.net/~helly/php/ext/spl/" target="_blank">SPL</a> vorhandene <a href="http://blog.ebene7.com/schlagwort/iterator/">Iteratoren</a> zu kontrollieren. Das ist einfach und hat sicherlich auch schon jeder einmal gemacht.</p>
<p>Damit ist dann zumindest der eine Teil, die Datenstruktur, für sich gekapselt. Was ist aber mit dem Teil, den wir wahrscheinlich häufiger verwenden werden? Wir nutzen Iteratoren in Schleifen und machen irgendwas mit den Elementen.<span id="more-3499"></span></p>
<pre>&lt;?php
foreach($list as $key =&gt; $item) {
  $item-&gt;doSomething();
}

// oder
$values = array();
foreach($list as $key =&gt; $item) {
  $values[] = $item-&gt;getSomething();
}</pre>
<p>In verschiedenen anderen Sprachen, Java, JavaScript etc., sieht man häufig, dass dort auch die Scheifen gekapselt sind. Warum probieren wir das nicht auch mal in PHP?</p>
<p>Ich werde das Beipiel bewusst einfach halten und wie gewohnt auf einige Fehlerbehandlungen verzichten, um den Code übersichtlich zu halten.</p>
<p>Als erstes erstellen wir eine Klasse &#8220;WalkableIterator&#8221; und lassen diese von ArrayIterator erben. Die beiden Methoden &#8220;each&#8221; und &#8220;walk&#8221; bilden später unsere beiden Beispiele ab.</p>
<pre>&lt;?php
class WalkableIterator extends ArrayIterator {
  public function each($method) {}
  public function walk($callback) {}
}</pre>
<p>Mit each() können wir eine bestimmte Methode auf jedem Element in unserem Iterator aufrufen. Dafür müssten hier natürlich diverse Fehlerbehandlungen rein was passieren soll, wenn das Element kein Objekt ist oder die Methode nicht existiert oder diese gar eine Exception wirft.</p>
<pre>&lt;?php
class WalkableIterator extends ArrayIterator {
  public function each($method) {
    $args = func_get_args();
    $method = array_shift($args);
    foreach($this as $item) {
      call_user_func_array( array($item, $method), $args );
    }
  }
  // ...
}</pre>
<p>Das ganze ist denkbar einfach: Die Methode nimmt als ersten Pflichtparameter den Methodennamen entgegen, die auf allen Elementen aufgerufen werden soll und der Rest bleibt flexibel und wird einfach nur durchgereicht.</p>
<p>Die Implementierung von walk() wird sogar noch einfacher, da hier keine Parameter weitergegeben werden müssen. Im produktiven Einsatz müssten auch hier noch die üblichen Fehlerbehandlungen rein.</p>
<pre>&lt;?php
class WalkableIterator extends ArrayIterator {
  // ...
  public function walk($callback) {
    foreach($this as $item) {
      call_user_func( $callback, $item );
    }
  }
}</pre>
<p>Soweit, so einfach&#8230; Was können wir jetzt damit machen? Bauen wir ein kleines Beispiel.</p>
<pre>&lt;?php
// Testklasse
class Person {
  private $name;
  public function __construct($name = 'unnamed') {
    $this-&gt;setName($name);
  }
  public function getName() {
    return $this-&gt;name;
  }
  public function setName($name) {
    $this-&gt;name = $name;
  }
}

// Testarray mit Objekten befüllen
$a = array();
for($i=1; $i &lt;= 10; $i++) {
  $a[] = new Person('Person ' . $i);
}

// Iterator erstellen und Namen ausgeben
$it = new WalkableIterator($a);

foreach($it as $item) {
  echo $item-&gt;getName() . '&lt;br/&gt;';
}

// Person 1
// ...
// Person 10</pre>
<p>Wollten wir nun allen Personenobjekten einen Namen geben, so könnten wir dafür each() verwenden.</p>
<pre>&lt;?php
$it-&gt;each('setName', 'PHP-Nerd');

// PHP-Nerd
// ...
// PHP-Nerd</pre>
<p>Wollen wir unsere Personen dann vielleicht doch wieder individueller benennen, so könnten wird das mit walk() und einem <a href="http://blog.ebene7.com/schlagwort/callback/">Callback</a> machen.</p>
<pre>$callback = function(Person $person) {
  static $count = 1;
  $person-&gt;setName( $person-&gt;getName() . ' ' . $count++ );
};

$it-&gt;walk($callback);</pre>
<pre>// PHP-Nerd 1
// ...
// PHP-Nerd 10</pre>
<p>&#8220;Was bringt uns das und warum so kompliziert?&#8221;, ist in dem Zusammenhang eine oft gehörte Frage.</p>
<p>Zunächst ist die Implementierung, wie das Beispiel sicher beweist, nicht kompliziert.</p>
<p>Die Vorteile sind kürzere Aufrufe im Code, weil wir keine Schleifen mehr schreiben müssen und durch die Kapselung verbessert sich auch die Wart- und Testbarkeit. Der Code existiert nur an einer Stelle und funktioniert überall nach dem selben Muster.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2012/07/31/walkable-iterator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SPL: Iterator vs. IteratorAggregate</title>
		<link>http://blog.ebene7.com/2010/12/01/spliterator-vs-iteratoraggregate/</link>
		<comments>http://blog.ebene7.com/2010/12/01/spliterator-vs-iteratoraggregate/#comments</comments>
		<pubDate>Wed, 01 Dec 2010 05:00:58 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[Schleife]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=2224</guid>
		<description><![CDATA[PHP bietet mit der SPL (StandardPHPLibrary) eine Vielzahl fertiger Iteratoren an, mit denen Daten in Schleifen verarbeitet werden können, aber auch zwei Interfaces durch die eigene Objekte iterierbar werden. Ganz klar, es handelt sich um die Interfaces Iterator und IteratorAggregate. &#8230; <a href="http://blog.ebene7.com/2010/12/01/spliterator-vs-iteratoraggregate/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>PHP bietet mit der <a href="http://www.php.net/~helly/php/ext/spl/" target="_blank">SPL (StandardPHPLibrary)</a> eine Vielzahl fertiger Iteratoren an, mit denen Daten in Schleifen verarbeitet werden können, aber auch zwei Interfaces durch die eigene Objekte iterierbar werden.</p>
<p>Ganz klar, es handelt sich um die Interfaces Iterator und IteratorAggregate. Was aber unterscheidet die beiden?</p>
<p><span id="more-2224"></span></p>
<p>Um den Aufbau der beiden Klassen gegenüberzustellen habe ich zwei einfache Beispiel-Klassen geschrieben, mit denen wir ein Array in einer foreach-Schleife auslesen können.</p>
<h3>Iterator</h3>
<p>Das Interface Iterator schreibt fünf Methoden vor, die zur Verarbeitung des Objektes in einer Schleife benötigt werden: <code>current(), next(), key(), valid()</code> und <code>rewind()</code>.</p>
<pre>&lt;?php
class TestA implements Iterator
{
  private $_items;

  public function __construct(array $items = array())
  {
    $this-&gt;_items = $items;
  }

  public function current()
  {
    return current($this-&gt;_items);
  }

  public function next()
  {
    next($this-&gt;_items);
  }

  public function key()
  {
    return key($this-&gt;_items);
  }

  public function valid()
  {
    return false !== current($this-&gt;_items);
  }

  public function rewind()
  {
    reset($this-&gt;_items);
  }
}</pre>
<p>Auf den ersten Blick lässt sich erkennen, dass relativ viel Code benötigt benötigt wird und dieser starr am Objekt hängt. Ok, für diesen Zweck hätte man auch den ArrayIterator nehmen können, aber dann gäbe es weniger zu gucken.</p>
<h3>IteratorAggregate</h3>
<p>Das zweite Iterface ist dagegen wesentlich schlanker, denn es kommt mit der einzigen Methode <code>getIterator()</code> aus.</p>
<pre>&lt;?php
class TestB implements IteratorAggregate
{
  private $_items;

  public function __construct(array $items = array())
  {
    $this-&gt;_items = $items;
  }

  public function getIterator()
  {
    return new ArrayIterator($this-&gt;_items);
  }
}</pre>
<p>Die Methode erzeugt einen externen Iterator und lagert damit die Funktionalität in eine andere Klasse aus. Dadurch bleibt unsere Klasse übersichtlich und das Iterator-Verhalten lässt sich einfach austauschen.</p>
<h3>Fazit</h3>
<p>Für einfache Strukturen würde ich das IteratorAggregate-Interface vorziehen, da es sehr einfach aufgebaut ist und unseren Code schlank und übersichtlich hält. Die Funktionalität ist zudem durch verschiedene externe Klassen variabel und viele Standardfälle können mit den SPL-Klassen abgedeckt werden.</p>
<p>Lässt sich eine Struktur aus irgendeinem Grund nicht an einen externen Iterator übergeben, bzw. will man für diesen speziellen Fall schreiben, dann kommt das Iterator-Interface zum Einsatz.</p>
<p>Genaugenommen lässt sich das mit den beiden Beispielklassen schon gut testen. Einfach in der Klasse TestB</p>
<pre>public function getIterator()
{
  return new ArrayIterator($this-&gt;_items);
}</pre>
<p>gegen</p>
<pre>public function getIterator()
{
  return new TestA($this-&gt;_items);
}</pre>
<p>austauschen und etwas damit rumspielen.</p>
<p>In der Anwendung sind beide später identisch:</p>
<pre>&lt;?php
$a = new TestA(array('A','B','C','D','E'));

foreach ($a as $k =&gt; $v) {
  echo "$k = $v &lt;br/&gt;";
}

$b = new TestB(array('A','B','C','D','E'));

foreach ($b as $k =&gt; $v) {
  echo "$k = $v &lt;br/&gt;";
}</pre>
<p>Viel Spaß damit! Eure Erkenntnisse zu dem Thema könnt ihr wie immer gerne in den Kommentaren verewigen&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2010/12/01/spliterator-vs-iteratoraggregate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Es ist ein Model und es sieht gut aus &#8211; Iterator</title>
		<link>http://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/</link>
		<comments>http://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/#comments</comments>
		<pubDate>Thu, 06 May 2010 05:00:37 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Countable]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Foreach]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Schleife]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=430</guid>
		<description><![CDATA[Nachdem sich unsere Klasse Custom_Model während der letzten Artikel gut entwickelt hat, werden wir daran heute gleich anknüpfen und das Iterator-Interface implementieren. Was kann unser Model dann, was es vorher noch nicht konnte? Durch die Verwendung des Interfaces können wir &#8230; <a href="http://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Nachdem sich unsere Klasse Custom_Model während der letzten Artikel gut entwickelt hat, werden wir daran heute gleich anknüpfen und das <a href="http://www.php.net/manual/de/class.iterator.php" target="_blank">Iterator-Interface</a> implementieren.</p>
<p>Was kann unser Model dann, was es vorher noch nicht konnte? Durch die Verwendung des Interfaces können wir die gespeicherten Daten in einer foreach-Schleife verarbeiten. Das kann z.B. beim erzeugen von Tabellen erforderlich sein.</p>
<p><span id="more-430"></span>Wie immer beginne ich mit einer Skizze der heutigen Erweiterungen.</p>
<pre>&lt;?php
interface Custom_Model_Interface
  extends ArrayAccess,
          Iterator,
          Countable
{
}</pre>
<p>Unser Interface Custom_Model_Interface erweitert zunächst das Iterator-Interface und auch <a href="http://www.php.net/manual/de/class.countable.php" target="_blank">Countable</a>. Dadurch lassen sich dann die Elemente des Objektes zählen und in Verbindung mit ArrayAccess auch beliebig in einer for-Schleife verarbeiten.</p>
<p>In unserer Klasse müssen wir nun die entsprechenden Methoden deklarieren.</p>
<pre>&lt;?php
class Custom_Model implements Custom_Model_Interface
{
  // ...

  public function current() {}
  public function key() {}
  public function next() {}
  public function rewind() {}
  public function valid() {}
  public function count() {}

// ...
}</pre>
<p>Jedem, der lange genug mit PHP arbeitet sollte nun was auffallen. Richtig! Wir halten unsere &#8220;Feldnamen&#8221; in einem Array und zu fast jeder Methode gibt es eine gleichnamige <a href="http://de3.php.net/manual/de/ref.array.php" target="_blank">Array-Funktion</a>.</p>
<p>Da wir aber an meistens an die Werte und nicht an die Namen der Felder wollen, müssen wir etwas tricksen.</p>
<p>Die erste Methode <code>current()</code> gibt das jeweilige Element an der Position des internen Zeigers zurück und entspricht damit der gleichnamigen Array-Funktion <a href="http://de3.php.net/manual/de/function.current.php" target="_blank"><code>current()</code></a>.</p>
<pre>public function current()
{
  return $this-&gt;_get(current($this-&gt;_keys));
}</pre>
<p>Das Gegenstück dazu stellt quasi <code>key()</code> dar, da es den Feldnamen der Position liefert.</p>
<pre>public function key()
{
  return $this-&gt;_keys[key($this-&gt;_keys)];
}</pre>
<p>Auf den ersten Blick mag diese Schreibweise vielleicht etwas verwirren, aber nur so bekommen wir den richtigen Schlüssel. <a href="http://de3.php.net/manual/de/function.key.php" target="_blank"><code>key()</code></a> gibt uns den aktuellen Schlüssel von $this-&gt;_keys zurück, wir wollen den Wert der jeweiligen Position haben.</p>
<p>Um nun in der Schleife den internen Zeiger bewegen zu können, brauchen wir <a href="http://de3.php.net/manual/de/function.next.php" target="_blank"><code>next()</code></a>.</p>
<pre>public function next()
{
  next($this-&gt;_keys);
}</pre>
<p>Wird das Objekt ein weiteres Mal mit foreach verarbeitet, so muss der interne Zeiger wieder auf die erste Position zurückgesetzt werden. Das Iterator-Interface schreibt dafür die Methode <code>rewind()</code> vor, die dann intern <a href="http://de3.php.net/manual/de/function.reset.php" target="_blank"><code>reset()</code></a> verwenden kann.</p>
<pre>public function rewind()
{
  reset($this-&gt;_keys);
}</pre>
<p>Innerhalb der Schleife wir überprüft, ob weitere Elemente vorhanden sind. Dazu wird <code>valid()</code> verwendet.</p>
<pre>public function valid()
{
  return current($this-&gt;_keys) !== false;
}</pre>
<p>Damit haben wir alles notwendige eingebaut, damit unser Model in einer foreach-Schleife ausgelesen werden kann.</p>
<pre>foreach($model as $key=&gt;$value) {
  echo $key . ' = ' . $value . '&lt;br/&gt;';
}</pre>
<p>Zuletzt gibt es dann auch noch die Methode <code>count()</code> des Countable-Interfaces, damit wir beliebig mit for-Schleifen über das Objekt iterieren können.</p>
<pre>public function count()
{
  return count($this-&gt;_keys);    
}</pre>
<p>und</p>
<pre>for($i=0; $i&lt;count($model); $i++) {
  echo $i . ' = ' . $model[$i] . '&lt;br/&gt;';
}</pre>
<p>Damit wären wir auch schon wieder am Ende. Beim nächsten Mal geht es dann weiter mit dem <a href="http://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/" target="_self">Observer-Pattern</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ebene7.com/2010/05/06/es-ist-ein-model-und-es-sieht-gut-aus-iterator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
