How to use PHP generators without foreach?

Here is a simple JavaScript generator (via: http://blog.carbonfive.com/2013/12/01/hanging-up-on-callbacks-generators-in-ecmascript-6/ )

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 

I'm trying to simulate something like this with PHP, but this is a bit of a headache.

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

Before I go any further, I get this error in PHP

Fatal error: generators cannot return values ​​using "return"

Well, maybe I'm just using a different income to get the final value? ...

 <?php function powGenerator() { yield pow((yield 'a'), (yield 'b')); } $g = powGenerator(); //=> Generator {#180} echo $g->send(10); //=> "b" echo $g->send(2); //=> 100 

Ok, so I got my meaning back, but there are two main problems.

  • Where is my "a" go? - Please note that in the JS example, I was able to access the values ​​of "a" and "b" , as well as the final result of 100 .

  • The generator is not done yet! - I need to call send extra time to complete the generator

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

From PHP Generator :: send

public mixed Generator::send ( mixed $value )

Sends the setpoint to the generator as a result of the current yield expression and resumes the generator.

If the generator does not have a yield expression when calling this method, first, before sending the value, first go to the first yield expression. Essentially, there is no need to “run” PHP generators with a call to Generator :: next () (as is done in Python).

Emphasis on "As such, there is no need to" calculate "PHP generators using Generator::next() ." OK, but what does that mean? I don’t need to “refuel” it, as an example of JavaScript, but the first received value is also swallowed.

Can someone explain how you are going to run generators without using foreach ?

+5
source share
1 answer

The first value received was not swallowed, you just never looked at it.

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

Then you send the values ​​twice and resume execution, $g->valid() is true after that, because you did not resume work after the third yield - the generator was not completed and there could be more to do. Consider:

 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 

This will output:

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

Now in PHP 7 you can return from the 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"; 

What outputs:

 a b bool(false) 100 

As for going through them without foreach - Generator implements Iterator , so he got the appropriate methods for processing it as follows: current , key , next , rewind and valid . With the caution that rewind will throw an exception if you call it on an already running generator.

An example that does this and also demonstrates a new generation of generators

 function letterGenerator() { yield from range('a', 'z'); } $g = letterGenerator(); while ($g->valid()) { echo $g->current(); $g->next(); } 

Output:

 abcdefghijklmnopqrstuvwxyz 
+8
source

Source: https://habr.com/ru/post/1233011/


All Articles