Jaka jest różnica między generatorem a tablicą?
Dzisiaj zespół PHP wydał PHP 5.5.0 wersja, która zawiera wsparcie dla generatorów . Czytanie dokumentacja, zauważyłem, że robi dokładnie to, co może zrobić z tablicą.
Zespół PHP generator przykład :
// Only PHP 5.5
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// Note that $i is preserved between yields.
yield $i;
}
}
$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
Wynik :
1
2
3
Ale mogę zrobić to samo używając tablic. I nadal mogę zachować kompatybilność z wcześniejszymi wersjami PHP.
Take a look :
// Compatible with 4.4.9!
function gen_one_to_three() {
$results = array();
for ($i = 1; $i <= 3; $i++) {
$results[] = $i;
}
return $results;
}
$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
Więc pytanie brzmi: Jaki jest cel istnienia tej nowej cechy? Muszę odtworzyć wszystkie przykłady dokumentacji bez używania nowej funkcji, zastępując ją tablicą.
Czy ktoś może podać dobre wyjaśnienie i może przykład, który niekoniecznie jest niemożliwy w starszych wersjach, ale korzystanie z generatorów może pomóc w rozwoju?
4 answers
Różnica polega na wydajności. Na przykład wiele języków innych niż PHP zawiera dwie funkcje range
, range()
i xrange()
. Jest to naprawdę dobry przykład generatorów i dlaczego z nich korzystać. Zbudujmy własne:
function range($start, $end) {
$array = array();
for ($i = $start; $i <= $end; $i++) {
$array[] = $i;
}
return $array;
}
To naprawdę proste. Jednak w przypadku dużych zakresów zajmuje to ogromną ilość pamięci. Jeśli spróbujemy uruchomić go z $start = 0
i $end = 100000000
, prawdopodobnie zabraknie nam pamięci!
Ale jeśli użyjemy generatora:
function xrange($start, $end) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
Teraz używamy pamięci stałej, jednak nadal mamy "tablicę" (podobną do struktury), którą możemy iterować (i używać z innymi iteratorami) w tej samej przestrzeni.
Nie zastępuje tablicy, ale zapewnia skuteczny sposób unikania potrzeby pamięci...
Ale zapewnia również oszczędności w zakresie generowania pozycji. Ponieważ każdy wynik jest generowany zgodnie z potrzebami, można opóźnić wykonanie (pobieranie lub obliczanie) każdego elementu, aż będzie potrzebny. Więc na przykład, jeśli potrzebujesz pobrać przedmiot z bazy danych i wykonaj skomplikowane przetwarzanie wokół każdego wiersza, możesz opóźnić to za pomocą generatora, aż faktycznie będziesz potrzebować tego wiersza:
function fetchFromDb($result) {
while ($row = $result->fetchArray()) {
$record = doSomeComplexProcessing($row);
yield $record;
}
}
Więc jeśli potrzebujesz tylko pierwszych 3 wyników, przetworzysz tylko trzy pierwsze rekordy.
Aby uzyskać więcej informacji, napisałem blog post na ten dokładnie temat.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 21:19:17
Generatory pozwalają na leniwą ocenę złożonych twierdzeń. W ten sposób oszczędzasz pamięć, ponieważ nie musisz przydzielać wszystkiego na raz.
Poza tym, że oba są iteracyjne, nie są prawie takie same. An {[0] } jest strukturą danych, generator nie jest.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 21:12:52
Tablica musi zawierać każdą wartość, którą zapętlasz, zanim zaczniesz zapętlać; generator tworzy każdą wartość "w locie" zgodnie z żądaniem, więc dużo mniej pamięci;
Tablica działa z wartościami, które zawiera, I musi być wstępnie wypełniona tymi wartościami; generator może tworzyć wartości według specjalnych kryteriów, które mają być używane bezpośrednio... np. ciąg fibonnaciego, czyli litery z alfabetu nie-A-Z (obliczane przez wartość liczbową UTF-8) skutecznie pozwalające alphaRange ("א", "א");
EDIT
function fibonacci($count) {
$prev = 0;
$current = 1;
for ($i = 0; $i < $count; ++$i) {
yield $prev;
$next = $prev + $current;
$prev = $current;
$current = $next;
}
}
foreach (fibonacci(48) as $i => $value) {
echo $i , ' -> ' , $value, PHP_EOL;
}
EDIT
Dla Zabawy, oto generator, który zwróci alfabet hebrajski jako znaki UTF-8
function hebrewAlphabet() {
$utf8firstCharacter = 1488;
$utf8lastCharacter = 1514;
for ($character = $utf8firstCharacter; $character <= $utf8lastCharacter; ++$character) {
yield html_entity_decode('&#'.$character.';', ENT_NOQUOTES, 'UTF-8');
};
}
foreach(hebrewAlphabet() as $character) {
echo $character, ' ';
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-29 12:42:51
Jak w Pythonie:
gdy iteracja nad zbiorem elementów zaczyna używać instrukcji for, generator jest uruchamiany. Gdy kod funkcji generatora osiągnie instrukcję "yield", generator zwraca jego wykonanie z powrotem do pętli for, zwracając nową wartość z zestawu. Funkcja generatora może wygenerować tyle wartości (ewentualnie nieskończonych), ile chce, otrzymując każdą z nich z kolei.
...Generatory wykonują instrukcje wydajności po kolei, zatrzymując się pomiędzy aby przywrócić wykonanie do głównej pętli for.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 21:35:37