2015-10-06 15 views
5

Ecco un semplice generatore di JavaScript (via: http://blog.carbonfive.com/2013/12/01/hanging-up-on-callbacks-generators-in-ecmascript-6/)Come utilizzare i generatori PHP senza 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 

Sto cercando di modellare qualcosa di simile con PHP, ma è un po 'di mal di testa.

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

Prima di andare oltre, ottengo questo errore in PHP

Fatal error: Generators cannot return values using "return"

Ok, forse mi limiterò a uso un altro rendimento per ottenere il valore finale fuori? ...

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

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

OK, così ho preso il mio valore schiena, ma ci sono due problemi principali qui

  1. Dove ha fatto il mio "a" andare? — Nota nell'esempio JS Sono stato in grado di accedere sia al valore "a" sia al valore "b" e al risultato finale 100.

  2. Il generatore non è ancora pronto! — devo chiamare send un tempo aggiuntivo per completare il generatore

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

da 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).

accento sulla "Come tale, non è necessario "prime" Generatori PHP con un Generator::next() ". OK, ma cosa significa veramente? Non devo "innescarlo" come nell'esempio JavaScript, ma anche il primo valore ceduto viene inghiottito.

Qualcuno può spiegare come si intende passare attraverso i generatori senza utilizzando un foreach?

risposta

8

Il primo valore di rendimento non è stato ingerito, non l'hai mai guardato.

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

Stai poi due volte l'invio di valori e di riprendere l'esecuzione, $g->valid() è true dopo questo perché non si è ripreso dopo il terzo yield - il generatore non è completo e ci possono essere più per poter fare . Considerate:

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 

questo sarà uscita:

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

Ora in PHP 7 si possibilereturn 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"; 

quali uscite:

a 
b 

bool(false) 
100 

Per quanto riguarda il rafforzamento attraverso di loro senza un foreach - Generator implementa Iterator, quindi è avuto metodi appropriati per trattarla come tale: current, key, next, rewind e valid. Con l'avvertenza che rewind genererà un'eccezione se la chiami su un generatore già avviato.

Un esempio che fa questo e dimostra anche PHP 7 del nuovo generator delegation:

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

$g = letterGenerator(); 

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

uscita:

abcdefghijklmnopqrstuvwxyz 
+0

Ok, l'uso di '' current' e next' è almeno coerente con gli attuali implementazioni di array, ma non essere in grado di specificare la fine di un generatore è davvero stupido, imo. La chiamata extra 'next()' per terminare il generatore rende davvero difficile costruire il proprio passo programmatico attorno a questo. La documentazione fa sembrare che i generatori PHP siano bravi a non dover "innescarli" come fa Python. Hanno comunque finito con un'API goffo. PHP classico. – naomik

+0

Il 'return' in PHP 7 risolve la mia preoccupazione ma in realtà non mi aiuta. PHP 7 probabilmente non sarà stabile per molto, molto tempo. Non riesco a vedere come i generatori esistenti potrebbero essere così miopi. Sembra che sia solo pratico usarli con 'foreach'. – naomik

+0

Comunque, grazie per il tuo aiuto. Continuerò semplicemente con uno stile di programmazione assolutamente imperativo. Questo è praticamente tutto ciò che PHP offre in modo affidabile, comunque. Niente di nuovo in PHP dev e. – naomik