sieci komputerowe, cisco, webmastering, php, css, xhtml, javascript, google, linux, windows server

Iteratory w PHP - część 2: własny iterator

Kategorie: PHP | 17 kwietnia 2007 14:05 | Odsłon: 4195 | Komentarzy: 3 | Permalink

W PHP5 pojawiła się bardzo interesująca możliwość - nadpisanie domyślnego sposobu iteracji własnych klas. Dotychczas konstrukcja (w wersjach wcześniejszych niż PHP5):

$klasa = new mojaklasa(); foreach($klasa as $name => $value) { // ... }

Pozwalała jedynie na operowanie właściwościach klasy. PHP5 pozwala to zmienić i stworzyć własne sposoby obsługi iteracji.

Wbudowane interfejsy

PHP w wersji 5 posiada zestaw wbudowanych interfejsów, których implementacja w klasie pozwala na nadpisanie domyślnych sposobów iteracji:

Interfejs Traversable

Podstawowym interfejsem jest Traversable. Każda klasa implementująca ten interfejs może być użyta z konstrukcją foreach. Interfejs Traversable nie posiada żadnych właściwości ani metod (jest pusty), dlatego nie powinien on byc implementowany bezpośrednio. Zamiast niego zaleca się implementowanie interfejsu Iterator lub IteratorAggregate.

Interfejs Iterator

Iterator jest głównym interfejsem, który definiuje metody, jakie należy zaimplementować aby poprawnie móc używać klasy w konstrukcji foreach.
Ten wbudowany w PHP5 interfejs prezentuje się tak:

interface Iterator extends Traversable { function current(); function key(); function next(); function rewind(); function valid(); }

Poniżej zamieszczam krótki opis jego metod:

  • void rewind() - przewija listę iteratora na początek
  • void next() - przechodzi do następnego elementu
  • bool valid() - zwraca true jeśli istnieją jeszcze nieprzetworzone elementy
  • mixed current() - zwraca wartość bieżącego elementu
  • mixed key() - zwraca klucz bieżącego elementu

Interfejs IteratorAggregate

Klasa może obsłużyć iterację także na drugi sposób - implementując interfejs IteratorAggregate wyglądający tak:

interface IteratorAggregate implements Traversable { function getIterator(); }

Interfejs ten posiada jedną metodę - Iterator getIterator(), która powinna tworzyć i zwracać obiekt iteratora. Interfejs ten jest szczególnie przydatny, gdy nie chcemy "mieszać" metod specyficznych danej klasy z metodami iteratora - pozwala nam on na odseparowanie kodu iteratora od kodu danej klasy.

W praktyce

Jako przykład zastosowania implementacji własnego iteratora w klasie zaprezentuję klasę do obsługi prostego katalogu stron.
Klasa ta zawiera kilka własnych metod, m.in. do dodawania do niej strony oraz do jej usuwania, poza tym implementuje ona interfejs Iterator, dzięki czemu przy jej pomocy możemy w łatwy sposób przeglądać dwa wybrane z niej pola - tytuł strony oraz jej adres.

Dane będą przechowywane w wielowymiarowej tablicy, choć oczywiście nic nie stoi na przeszkodzie, aby były przechowywane gdzie indziej. Nie chcąc jednak komplikować kodu, wybrałem właśnie tą metodę.

class webcatalog implements Iterator { private $data=array(); // tablica do skladowania danych private $ipointer=0; // pomocniczy wskaznik dla metod iteratora /* * Funkcja sluzaca do dodawania stron do katalogu */ public function addPage($url,$title,$mail,$description,$keywords) { $this->data[]=array( "url"=>$url, "title"=>$title, "mail"=>$mail, "description"=>$description, "keywords"=>$keywords ); } /* * Funkcja do usuwania stron na podstawie adresu URL */ public function delPageByURL($url) { foreach($this->data as $cnt => $item) { if($item["url"]==$url) { unset($this->data[$cnt]); return true; } } return false; } /* * Przechodzimy do czesci wlasciwej, czyli implementacji iteratora */ public function current() { return $this->data[$this->ipointer]["title"]; } public function key() { return $this->data[$this->ipointer]["url"]; } public function next() { $this->ipointer++; } public function rewind() { $this->ipointer=0; } public function valid() { return ($this->ipointer<sizeof($this->data)); } }

Teraz spójrzmy jak nasza przykładowa klasa działa:

$wc=new webcatalog(); /* * Dodajemy strony do naszego katalogu przy pomocy metody addPage */ $wc->addPage("http://luktom.net/","luktom online blog", "Blog o sieciach komputerowych, routerach Cisco i webmasteringu", "sieci komputerowe, cisco, routery, webmastering, php" ); $wc->addPage("http://ccie.pl", "Forum CCIE.pl", "Forum CCIE.pl", "cisco, ccna, ccnp, ccie, routery" ); /* * Dzieki implementacji interfejsu Iterator, mozemy ladnie wyswietlic * dane, przy uzyciu konstrukcji foreach */ foreach($wc as $url => $title) { print "$title ($url)<br/>"; }

Jak widać, iteratory są bardzo przyjemnym dodatkiem do codziennego programowania :)

Zobacz także

Wpisy o podobnej tematyce

Amuuuuused ;)

17 kwietnia 2007 15:15
Kolejny artykuł o iteratorach. Ale już 101., to może byś się rozpisał o jakimś ich przydatnym zastosowaniu?

Anyway, właściwość $ipointer można o kant dupy potłuc w tym przykładzie. ;) Zupełnie jest niepotrzebna. Spójrz na moją implementację: http://www.patternsforphp.com/wiki/Iterator#Implementating_an_Album_Iterator

Jest - eee ;P - chyba ździebko lepsza. ;)

Samael

30 kwietnia 2008 11:24
Wybacz Amuused ale je??eli mam uzywac p?tli foreach to nie chce mi sie bawi? z Currentami, Foreach ma przejechac i wy??wietli? mi ca??a tablice a nie pomija? warto??ci pocz?tkowej. I jako?? mnie nei zaskoczy??es uzywajac niczego innego jak tylko zwyk??ych arrayowych funkcji

Samael

30 kwietnia 2008 11:29
A chyba najbardziej widac to ze w sumie iterator nie musi operowac tylko na tablicach ;) wtedy pointer bywa przydatny

Dodaj komentarz

Token

Statystyka
Ładowanie...