PHP 8.4.1 Released!

Generator::send

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

Generator::sendÜretece bir değer gönderir

Açıklama

public Generator::send(mixed $value): mixed

Geçerli yield ifadesinin sonucu olarak belirtilen değeri gönderir ve üretecin kaldığı yerden devam etmesini sağlar.

Bu yöntem çağrıldığında üreteç bir yield ifadesinde değilse, değeri göndermeden önce üreteci ilk yield ifadesine ilerletir. Yani, PHP üretecini bir Generator::next() çağrısıyla "iteklemek" gerekmez(Python'da yapıldığı gibi).

Bağımsız Değişkenler

value

Üretece gönderilecek değer. Bu değer üretecin geçerli yield ifadesinin dönüş değeri olacaktır.

Dönen Değerler

yield ifadesinin sonucu ile döner.

Örnekler

Örnek 1 - Değer yerleştirmek içinGenerator::send() kullanımı

<?php
function printer() {
echo
"Ben yazıcıyım!".PHP_EOL;
while (
true) {
$string = yield;
echo
$string.PHP_EOL;
}
}

$printer = printer();
$printer->send('Merhaba Dünya!');
$printer->send('Elveda Dünya!');
?>

Yukarıdaki örneğin çıktısı:

Ben yazıcıyım!
Merhaba Dünya!
Elveda Dünya!

add a note

User Contributed Notes 5 notes

up
71
sfroelich01 at sp dot gm dot ail dot am dot com
11 years ago
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
?>
up
9
php at didatus dot de
3 years ago
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+
up
4
anonymous at example dot com
5 years ago
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 X 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
up
11
sergei dot solomonov at gmail dot com
11 years ago
<?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!
up
1
baohx2000 at gmail dot com
5 years ago
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 = [];
}
}
}
To Top