request('GET', '/foo'); * $promise->then(function($value) { * * return $httpClient->request('DELETE','/foo'); * * })->then(function($value) { * * return $httpClient->request('PUT', '/foo'); * * })->error(function($reason) { * * echo "Failed because: $reason\n"; * * }); * * Example with coroutines: * * coroutine(function() { * * try { * yield $httpClient->request('GET', '/foo'); * yield $httpClient->request('DELETE', /foo'); * yield $httpClient->request('PUT', '/foo'); * } catch(\Throwable $reason) { * echo "Failed because: $reason\n"; * } * * }); * * @return \Sabre\Event\Promise * * @psalm-template TReturn * @psalm-param callable():\Generator $gen * @psalm-return Promise * * @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License */ function coroutine(callable $gen): Promise { $generator = $gen(); if (!$generator instanceof Generator) { throw new \InvalidArgumentException('You must pass a generator function'); } // This is the value we're returning. $promise = new Promise(); /** * So tempted to use the mythical y-combinator here, but it's not needed in * PHP. */ $advanceGenerator = function () use (&$advanceGenerator, $generator, $promise) { while ($generator->valid()) { $yieldedValue = $generator->current(); if ($yieldedValue instanceof Promise) { $yieldedValue->then( function ($value) use ($generator, &$advanceGenerator) { $generator->send($value); $advanceGenerator(); }, function (Throwable $reason) use ($generator, $advanceGenerator) { $generator->throw($reason); $advanceGenerator(); } )->otherwise(function (Throwable $reason) use ($promise) { // This error handler would be called, if something in the // generator throws an exception, and it's not caught // locally. $promise->reject($reason); }); // We need to break out of the loop, because $advanceGenerator // will be called asynchronously when the promise has a result. break; } else { // If the value was not a promise, we'll just let it pass through. $generator->send($yieldedValue); } } // If the generator is at the end, and we didn't run into an exception, // We're grabbing the "return" value and fulfilling our top-level // promise with its value. if (!$generator->valid() && Promise::PENDING === $promise->state) { $returnValue = $generator->getReturn(); // The return value is a promise. if ($returnValue instanceof Promise) { $returnValue->then(function ($value) use ($promise) { $promise->fulfill($value); }, function (Throwable $reason) use ($promise) { $promise->reject($reason); }); } else { $promise->fulfill($returnValue); } } }; try { $advanceGenerator(); } catch (Throwable $e) { $promise->reject($e); } return $promise; } __halt_compiler();----SIGNATURE:----qfwkQTbTvUjknACWk/6Jk7WHPW3PqVVU/ETSds8y67vuP0V4P/i8wgPVL086bqd82Rjjt/XEYzMuTUxPmkQgK1fZwsrvofYUBhE0LE/1+TOamNLTsaj/mNXxkXvjTMSJZC1PahHX0lN1TydDSKBBnP/I8o25BrfGi4bpYUFnGIOeuNmkZxlpYiZSkf2SX8GBxzdQ4yQ0F4dkqmd9QikwmymFRx/92QEXR1BQ7ji+NybB5L2lN2ATVMQLNIVuuNVhm1jGKtHti5pkgLkKf0va0ZwgtoziSmX4ZPbEQGTatDF2YwsqywzVxd7FqzAavU80fqsvsXxHq7eU/vANx8Q4EvlKR+3uNQ772Djldd0BrOhgyq0Q0K7QbBBM342guiJfCmqyqWvx9yGm03cFtUcpV3SsfpYaiS7zTzpwFNriNavs7X+nkLA+1ydVWPdST/PJ6kJucjgu31zA2aHXTeIkbX0hSFOAwaCtQqbRWDv9YPt2OAj0QZfxVNaYSKN057cryrf6vPU4xtGg+19ov94yfcGJhOvmfQUxqa6s52vikeEZyy9GIkNIwMeOSbesUqTXdZ4YpefKSaEKD5McmueyKrbetrDEpycPrOKsawf2DRdo6QMjMcwg2T4WlKTkfyJsOVvbPBmWS0XeZolKx5zMcTQJNyo+sALPuA6X/+lUWA8=----ATTACHMENT:----MjQ4OTM0ODM4MjMwMDk0MyAyODYyMjY1OTM4ODc0Njg2IDc4Nzk5Mjg1NjE1NDAwOTM=