/** * Handle resolving generators already done. * @param GeneratorContainer $gc * @return PromiseInterface */ private function processGeneratorContainerDone(GeneratorContainer $gc) { // If exception has been thrown in generator, we have to propagate it as rejected value if ($gc->thrown()) { return new RejectedPromise($gc->getReturnOrThrown()); } // Now we normalize returned value $returned = YieldableUtils::normalize($gc->getReturnOrThrown(), $gc->getYieldKey()); $yieldables = YieldableUtils::getYieldables($returned, [], $this->runners); // If normalized value contains yieldables, we have to chain resolver if ($yieldables) { $deferred = new Deferred(); return $this->promiseAll($yieldables, true)->then(YieldableUtils::getApplier($returned, $yieldables, [$deferred, 'resolve']), [$deferred, 'reject'])->then(function () use($yieldables, $deferred) { $this->runners = array_diff_key($this->runners, $yieldables); return $deferred->promise(); }); } // Propagate normalized returned value return new FulfilledPromise($returned); }
public function testExternalException() { $gen = (function () { $this->assertInstanceOf(\RuntimeException::class, (yield CoInterface::SAFE => null)); (yield null); })(); $con = new GeneratorContainer($gen); $con->key() === CoInterface::SAFE ? $con->send(new \RuntimeException()) : $con->throw_(new \RuntimeException()); $this->assertTrue($con->valid()); $this->assertFalse($con->thrown()); $gen = (function () { (yield null); (yield null); })(); $con = new GeneratorContainer($gen); $con->key() === CoInterface::SAFE ? $con->send(new \RuntimeException()) : $con->throw_(new \RuntimeException()); $this->assertFalse($con->valid()); $this->assertTrue($con->thrown()); $this->assertInstanceOf(\RuntimeException::class, $con->getReturnOrThrown()); }