Generator::send

(PHP 5 >= 5.5.0)

Generator::sendSend a value to the generator

Описание

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

Список параметров

value

Value to send into the generator. This value will be the return value of the yield expression the generator is currently at.

Примеры

Пример #1 Using Generator::send() to inject values

<?php
function printer() {
    while (
true) {
        
$string = yield;
        echo 
$string;
    }
}

$printer printer();
$printer->send('Hello world!');
$printer->send('Bye world!');
?>

Результат выполнения данного примера:

Hello world!
Bye world!

Возвращаемые значения

Returns the yielded value.

Коментарии

Reading the example, it is a bit difficult to understand what exactly to do with this. The example below is a simple example of what you can do this.

<?php
function nums() {
    for (
$i 0$i 5; ++$i) {
               
//get a value from the caller
       
$cmd = (yield $i);
       
        if(
$cmd == 'stop')
            return;
//exit the function
       
}     
}

$gen nums();
foreach(
$gen as $v)
{
    if(
$v == 3)//we are satisfied
       
$gen->send('stop');
   
    echo 
"{$v}\n";
}

//Output
0
1
2
3
?>
2013-07-17 15:11:41
http://php5.kiev.ua/manual/ru/generator.send.html
<?php
function foo() {
   
$string = yield;
    echo 
$string;
    for (
$i 1$i <= 3$i++) {
        yield 
$i;
    }
}

$generator foo();
$generator->send('Hello world!');
foreach (
$generator as $value) echo "$value\n";
?>

This code falls with the error:
PHP Fatal error:  Uncaught exception 'Exception' with message 'Cannot rewind a generator that was already run'.
foreach internally calls rewind, you should remember this!
2013-10-08 21:30:38
http://php5.kiev.ua/manual/ru/generator.send.html
As of 7.3, the behavior of a generator in a foreach loop depends on whether or not it expects to receive data. Relevant if you are experiencing "skips".

<?php
class implements IteratorAggregate {
    public function 
getIterator(){
        yield from [
1,2,3,4,5];
    }
    public function 
getGenerator(){
        foreach (
$this as $j => $each){
            echo 
"getGenerator(): yielding: {$j} => {$each}\n";
           
$val = (yield $j => $each);
            yield; 
// ignore foreach's next()
           
echo "getGenerator(): received: {$j} => {$val}\n";
        }
    }
}
$x = new X;

foreach (
$x as $i => $val){
    echo 
"getIterator(): {$i} => {$val}\n";
}
echo 
"\n";

$gen $x->getGenerator();
foreach (
$gen as $j => $val){
    echo 
"getGenerator(): sending:  {$j} => {$val}\n";
   
$gen->send($val);
}
?>

getIterator(): 0 => 1
getIterator(): 1 => 2
getIterator(): 2 => 3
getIterator(): 3 => 4
getIterator(): 4 => 5

getGenerator(): yielding: 0 => 1
getGenerator(): sending:  0 => 1
getGenerator(): received: 0 => 1
getGenerator(): yielding: 1 => 2
getGenerator(): sending:  1 => 2
getGenerator(): received: 1 => 2
getGenerator(): yielding: 2 => 3
getGenerator(): sending:  2 => 3
getGenerator(): received: 2 => 3
getGenerator(): yielding: 3 => 4
getGenerator(): sending:  3 => 4
getGenerator(): received: 3 => 4
getGenerator(): yielding: 4 => 5
getGenerator(): sending:  4 => 5
getGenerator(): received: 4 => 5
2019-06-21 13:38:01
http://php5.kiev.ua/manual/ru/generator.send.html
I have found that inverse generators (using $x = yield) is a great way to handle chunked batch processing. As data is being iterated, once a specific count has been fed to the generator, it processes and resets the data. For example, you could do a batch mysql insert every 500 records.

Example (note the handling of null, which you would send to the generator to handle stragglers after the previous batch)

function importer()
{
  $max = 500;
  $items = [];
  while (true) {
    $item = yield;
    if ($item !== null) {
      $items[] = yield;
    }
    if ($item === null || count($items) >= $max) {
       // do batch operations
       $items = [];
    }
  }
}
2019-10-24 22:15:53
http://php5.kiev.ua/manual/ru/generator.send.html
If you want to use generator::send() within a foreach loop, you will most likely get an unexpected result. The Generator::send() method resumes the generator, which means the pointer within the generator is moved to the next element in the generator list.

Here is an example:

<?php

class ApiDummy
{
    private static 
$apiDummyData = ['a''b''c''d''e'];

    public static function 
getAll(): Generator {
        foreach (
self::$apiDummyData as $entry) {
            echo 
'yielding $elem' PHP_EOL;
           
$newElem = (yield $entry);
            echo 
'yield return: ' $newElem PHP_EOL;
        }
    }
}

$generator ApiDummy::getAll();

// example iteration one with unexpected result
foreach ($generator as $elem) {
    echo 
'value from generator: ' $elem PHP_EOL;
   
$generator->send($elem '+');
}

// example iteration two with the expected result
while ($generator->valid()) {
   
$elem $generator->current();
    echo 
'value from generator: ' $elem PHP_EOL;
   
$generator->send($elem '+');
}
?>

The result of example iteration one:
yielding $elem
value from generator: a
yield return: a+
yielding $elem
yield return:
yielding $elem
value from generator: c
yield return: c+
yielding $elem
yield return:
yielding $elem
value from generator: e
yield return: e+

As you can see, the values b and d are not printed out and also not extended by the + sign.
The foreach loop receives the first yield and the send call causes a second yield within the first loop. Therefor the second loop already receives the third yield and so on.

To avoid this, one solution could be to use a while loop and the Generator::send() method to move the generator cursor forward and the Generator::current() method to retrieve the current value. The loop can be controlled with the Generator::valid() method which returns false, if the generator has finished. See example iterator two. 

The expected result of example iteration two:
yielding $elem
value from generator: a
yield return: a+
yielding $elem
value from generator: b
yield return: b+
yielding $elem
value from generator: c
yield return: c+
yielding $elem
value from generator: d
yield return: d+
yielding $elem
value from generator: e
yield return: e+
2021-05-10 23:09:38
http://php5.kiev.ua/manual/ru/generator.send.html

    Поддержать сайт на родительском проекте КГБ