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?

Author: hakre, 2013-06-21

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.

 57
Author: ircmaxell,
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.

 13
Author: TimWolla,
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, ' ';
}
 11
Author: Mark Baker,
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.

-learnpython.org

 2
Author: Luigi Siri,
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