/** * Resume execution of a suspended coroutine by passing it an exception. * * @param StrandInterface $strand The strand that is executing the coroutine. * @param Exception $exception The exception to send to the coroutine. */ public function resumeWithException(StrandInterface $strand, Exception $exception) { $throwException = true; $preventDefault = function () use(&$throwException) { $throwException = false; }; $strand->emit('error', [$strand, $exception, $preventDefault]); $strand->emit('exit', [$strand]); $strand->removeAllListeners(); $strand->pop(); $strand->suspend(); if ($throwException) { throw $exception; } }
/** * Start the coroutine. * * @param StrandInterface $strand The strand that is executing the coroutine. */ public function call(StrandInterface $strand) { $method = [$strand->kernel()->api(), $this->name]; if (!is_callable($method)) { $strand->throwException(new BadMethodCallException('The kernel API does not have an operation named "' . $this->name . '".')); return; } $strand->pop(); $arguments = $this->arguments; array_unshift($arguments, $strand); // If the kernel API implementation returns a non-null value it is // treated as a coroutine to be executed. This allows implementation of // kernel API operations to be implemented as generators. $coroutine = call_user_func_array($method, $arguments); if (null !== $coroutine) { $strand->call($coroutine); } }