2015-10-06 13 views
5

Oto prosty generator JavaScript (przez: http://blog.carbonfive.com/2013/12/01/hanging-up-on-callbacks-generators-in-ecmascript-6/)Jak korzystać z generatorów PHP bez foreach?

function* powGenerator() { 
    var result = Math.pow(yield "a", yield "b"); 
    return result; 
} 

var g = powGenerator(); 
console.log(g.next().value); // "a", from the first yield 
console.log(g.next(10).value); // "b", from the second 
console.log(g.next(2).value); // 100, the result 

Próbuję modelować coś podobnego z PHP, ale jest to trochę z bólem głowy.

<?php 
function powGenerator() { 
    return pow((yield 'a'), (yield 'b')); 
} 

Zanim pójdę dalej, mam ten błąd w PHP

Fatal error: Generators cannot return values using "return"

Ok, więc może ja po prostu użyć innego wydajność, aby uzyskać ostateczną wartość out? ...

<?php 
function powGenerator() { 
    yield pow((yield 'a'), (yield 'b')); 
} 

$g = powGenerator(); //=> Generator {#180} 
echo $g->send(10); //=> "b" 
echo $g->send(2); //=> 100 

OK, więc mam z powrotem moje wartości, ale nie ma tu dwa główne problemy

  1. Skąd mój "a" iść? — Zauważ, że w przykładzie JS mogłem uzyskać dostęp zarówno do uzyskanych wartości "a", jak i "b", a także do końcowego wyniku 100.

  2. Generator wciąż nie jest gotowy! — Muszę zadzwonić send dodatkowego czasu na wykonanie generatora

    $g->valid(); //=> true 
    $g->send('?'); //=> null 
    $g->valid(); //=> false 
    

Od PHP Generator::send

public mixed Generator::send (mixed $value)

Sends the given value to the generator as the result of the current yield expression and resumes execution of the generator.

If the generator is not at a yield expression when this method is called, it will first be let to advance to the first yield expression before sending the value. As such it is not necessary to "prime" PHP generators with a Generator::next() call (like it is done in Python).

nacisk na „Jako takie nie jest konieczne do "prime" Generatory PHP z Generator::next() ". OK, ale co to naprawdę znaczy? Nie muszę "zaliczyć" go tak, jak przykład JavaScriptu, ale pierwsza uzyskana wartość również zostaje połknięta.

Czy ktoś może wyjaśnić, w jaki sposób ma przejść przez generatory bez przy użyciu foreach?

Odpowiedz

8

Pierwsza dała wartość nie został połknięty, nigdy nie patrzył na niego.

$g = powGenerator(); 
echo $g->current(); //a 

Ty następnie dwukrotnie wysyłając w wartościach i wznawianie wykonania, $g->valid() jest true po to, ponieważ nie zostały wznowione po trzecim yield - generator nie jest kompletna i nie może być bardziej na to, aby zrobić . Rozważmy:

function powGenerator() { 
    yield pow((yield 'a'), (yield 'b')); 
    echo "Okay, finishing here now!\n"; 
} 

$g = powGenerator(); 
echo $g->current(), "\n"; //a 
echo $g->send(10), "\n"; //b 
echo $g->send(2), "\n"; //100 
$g->next();    // Resumes execution of the generator, 
          // which prints its own message and completes. 
var_dump($g->valid()); //false 

to będziesz wyjście:

a 
b 
100 
Okay, finishing here now! 
bool(false) 

Teraz w PHP 7 ty możereturn from a generator.

function powGenerator() { 
    return pow((yield 'a'), (yield 'b')); 
    echo "This will never print."; 
} 

$g = powGenerator(); 
echo $g->current(), "\n"; //a 
echo $g->send(10), "\n"; //b 
echo $g->send(2), "\n"; // Prints just the newline, you're moving on 
          // to a return which you must get explicitly. 
var_dump($g->valid()); // Generator complete, you're free to get the return. 
echo $g->getReturn(), "\n"; 

które wyjścia:

a 
b 

bool(false) 
100 

chodzi o wzmocnienie przez nich bez foreach - Generator realizuje Iterator, więc nie ma to odpowiednie metody, aby traktować go jako takie: current, key, next, rewind i valid. Z zastrzeżeniem, że rewind wyrzuci wyjątek, jeśli wywołasz go na generatorze, który już się rozpoczął.

Przykładem, który robi to, a także pokazuje, PHP 7 nowego generator delegation:

function letterGenerator() { 
    yield from range('a', 'z'); 
} 

$g = letterGenerator(); 

while ($g->valid()) { 
    echo $g->current(); 
    $g->next(); 
} 

wyjściowa:

abcdefghijklmnopqrstuvwxyz 
+0

Ok, użycie '' next' current' i jest co najmniej zgodne z istniejącymi implementacje tablic, ale niemożność określenia końca generatora jest naprawdę głupia, imo. Dodatkowe wywołanie 'next()' w celu zakończenia generatora sprawia, że ​​naprawdę trudno jest zbudować własne programowe przechodzenie wokół tego. Dokumentacja sprawia, że ​​brzmi to tak, jakby generatory PHP świetnie się nie musiały "zagruntować" tak, jak robi to Python. W każdym razie kończą się przylegającym API. Klasyczny PHP. – naomik

+0

"Zwrot" w PHP 7 rozwiązuje mój problem, ale tak naprawdę nie pomaga mi to. PHP 7 prawdopodobnie nie będzie stabilne przez długi, długi czas. Nie rozumiem, jak istniejące generatory mogą być tak krótkowzroczne. Wydaje się, że praktyczne jest użycie ich z 'foreach'. – naomik

+0

W każdym razie, dziękuję za pomoc. Będę trzymać się absolutnie imperatywnego stylu programowania. W zasadzie to wszystko, co PHP zapewnia mi niezawodnie. Nic nowego w PHP dev i. – naomik