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
Related posts:
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.