Собственно сабж, допустим у нас есть корутинка:
foreach ($items as $item) {
yield $item;
}
// foreach (myfoo() as $item) ...
Возвращает ссылку на итератор "итемов", а вот такая подменяет их:
foreach ($items as &$item) {
$item = yield;
}
// while ($iterator = myfoo()) { $iterator->send(23); }
Если совместить, получаем примерно такой вариант:
foreach ($items as &$item) {
$item = (yield $item);
}
// while ($iterator = myfoo()) { $iterator->current() === 42 ?: $iterator->send(23); }
В последнем случае происходит сдвиг итераций и вместо, допустим, 10 итераций мы получаем 5 с шагом 2. Для исправления этого можно воспользоваться таким вариантом:
foreach ($items as &$item) {
$item = yield (yield $item);
}
В этом случае можно и "читать" и "писать", но это лишь костыль, т.к. пропустить "тик" записи невозможно, произойдёт дублирование текущего.
Можно попробовать передать генератор по ссылке в качестве аргумента:
function myfoo(Generator $writer = null): Generator
{
foreach ($items as &$item) {
yield $item;
if ($writer !== null) {
$item = $writer->current(); // $writer->next() ?
}
}
}
// myfoo(yield ээээээ.... А дальше что писать? На этом мои полномочия всё (с)
Что-то вообще не могу придумать никаких универсальных решений, чтобы функцию можно было использовать как на чтение, так и на чтение + запись.
Есть хоть какие-то идеи? =)
UPD: Придумался вот такой вариант:
foreach ($items as &$item) {
$data = (yield $item);
if ($data !== null) {
$item = $data;
yield $item;
}
}
Но проблема в том, что он пишет в элемент N+1, а не текущий. Т.е. можно лишь внедряться в данные после текущего "тика", а не подменять их, оставаясь на текущем =(
$i = 0;
foreach ($reader = myfoo() as $value) {
echo ++$i . ') ' . $value . "\n";
$reader->send($i);
}
В результате получим что-то вроде:
1) 2
2) 3
3) 4
и т.д
.