Generatory w PHP
Dzisiaj kolejny post z nieoficjalnej serii „zaprzyjaźnij się z PHP” 😛 a dokładnie z php 5.3. Opiszę w nim jak zbudować generator. Czym jest generator ? Jak wyjaśnia nam Wikipedia generator jest rodzajem Iteratora, który zamiast zwracać wygenerowaną wcześniej zawartość oblicza nam ją wraz z kolejnym przebiegiem, dzięki czemu nie musimy od razu pobierać np. całej zawartości jakiejś kolekcji.
Nasz mały generator będzie implementował interfejs „Iterator” i pobierał w konstruktorze jako swój argument dowolną anonimową funkcję, która będzie generować kolejny wynik.
Kod:
class Generator implements Iterator { protected $_function; protected $_maxN; protected $_n = 0; public function __construct($function, $maxN) { $this->_function = $function; $this->_maxN = $maxN; } public function current() { $fFunc = $this->_function; return $fFunc($this->_n); } public function key() { return $this->_n; } public function next() { $this->_n++; } public function rewind() { $this->_n = 0; } public function valid() { if ($this->_n < $this->_maxN) { return true; } return false; } }
Nasz generator użyjemy do wygenerowania pierwszych n elementów ciągu fibonnaciego. Najpierw funkcja:
$cFib = function($n) use (&$cFib) { if ($n == 0) { return 0; } if ($n == 1) { return 1; } return $cFib($n - 1) + $cFib($n - 2); };
Jak widzimy jest to klasyczna implementacja funkcji obliczającej kolejny element ciągu fibonacciego. Z rzeczy które warto zauważyć – jest to domknięcie (closure) i aby funkcja mogła się rekurencyjnie wywołać musi dostać referencje do samej siebie (trochę jest to hak ale inaczej się nie da, __FUNCTION__ nie działa tak jak powinno).
Zastosowanie:
$oGenerator = new Generator($cFib, 5); foreach($oGenerator as $n => $value){ echo $n, ' ', $value, '<br/>'; }
Wynik:
0 0
1 1
2 1
3 2
4 3
Koniec końców uzyskaliśmy wygodną klasę do generowania kolejnych wartości. Przy odrobinie większym wysiłku, można by do implementować jeszcze interfejs ArrayAccess i mieć już całkowitą iluzję obcowania z tablicą –
echo $oGenerator[4]; //zwroci 3
Wojciech, szerzej opiszę tą funkcjonalność na swoim blogu bo to jest fajna rzecz. Jak skończę to się odezwę.
A mam to zaimplementowane w swoim FW jako mapę.
cojack – czyli jednak to co piszesz to framework 😀
@cojack – cieszę się, że podchwyciłeś temat, czekam na kreatywne rozwinięcie tematu 😉
Ty no nie czepiaj się, już mi wookieb nawytykał. Także nie będę się dłużej z tym bronił, no niech Wam będzie.