/**
* Create a new generator spy.
*
* @param Call $call The call from which the generator originated.
* @param Generator $generator The generator.
* @param CallEventFactory $callEventFactory The call event factory to use.
* @param bool $isGeneratorImplicitNextSupported True if implicit generator next() behavior is supported.
*
* @return Generator The newly created generator spy.
*/
public static function createGeneratorSpy(Call $call, Generator $generator, CallEventFactory $callEventFactory, $isGeneratorImplicitNextSupported)
{
$call->addIterableEvent($callEventFactory->createUsed());
$isFirst = true;
$received = null;
$receivedException = null;
while (true) {
$thrown = null;
try {
if ($isFirst) {
if (!$isGeneratorImplicitNextSupported) {
$generator->next();
}
} else {
if ($receivedException) {
$generator->throw($receivedException);
} else {
$generator->send($received);
}
}
if (!$generator->valid()) {
$call->setEndEvent($callEventFactory->createReturned(null));
break;
}
} catch (Throwable $thrown) {
// re-thrown after recording
} catch (Exception $thrown) {
// re-thrown after recording
}
if ($thrown) {
$call->setEndEvent($callEventFactory->createThrew($thrown));
throw $thrown;
}
$key = $generator->key();
$value = $generator->current();
$received = null;
$receivedException = null;
$call->addIterableEvent($callEventFactory->createProduced($key, $value));
try {
$received = (yield $key => $value);
$call->addIterableEvent($callEventFactory->createReceived($received));
} catch (Exception $receivedException) {
$call->addIterableEvent($callEventFactory->createReceivedException($receivedException));
}
$isFirst = false;
unset($value);
}
}