diff --git a/lib/functions.php b/lib/functions.php index cc54684..4dffad5 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -287,7 +287,7 @@ namespace Amp\Promise * This function is the same as some() with the notable exception that it will never fail even * if all promises in the array resolve unsuccessfully. * - * @param Promise[] $promises + * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises * * @return \Amp\Promise * @@ -303,7 +303,7 @@ namespace Amp\Promise * promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to * the array of promises. * - * @param \Amp\Promise[] $promises Array of only promises. + * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises Array of only promises. * * @return \Amp\Promise * @@ -354,7 +354,7 @@ namespace Amp\Promise /** * Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail. * - * @param \Amp\Promise[] $promises Array of only promises. + * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises Array of only promises. * * @return \Amp\Promise * @@ -407,7 +407,7 @@ namespace Amp\Promise * * The returned promise will only fail if the given number of required promises fail. * - * @param \Amp\Promise[] $promises Array of only promises. + * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises Array of only promises. * @param int $required Number of promises that must succeed for the returned promise to succeed. * * @return \Amp\Promise @@ -471,6 +471,38 @@ namespace Amp\Promise return $result; } + + /** + * Wraps a promise into another promise, altering the exception or result. + * + * @param \Amp\Promise|\React\Promise\PromiseInterface $promise + * @param callable $callback + * @return Promise + */ + function wrap($promise, callable $callback): Promise + { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } elseif (!$promise instanceof Promise) { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + + $deferred = new Deferred(); + + $promise->onResolve(function (\Throwable $exception = null, $result) use ($deferred, $callback) { + try { + $result = $callback($exception, $result); + } catch (\Throwable $exception) { + $deferred->fail($exception); + + return; + } + + $deferred->resolve($result); + }); + + return $deferred->promise(); + } } namespace Amp\Iterator diff --git a/test/WrapTest.php b/test/WrapTest.php new file mode 100644 index 0000000..5db3863 --- /dev/null +++ b/test/WrapTest.php @@ -0,0 +1,41 @@ +promise(), function () { + return 2; + }); + + $deferred->resolve(1); + + $result = Promise\wait($promise); + + $this->assertSame(2, $result); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage bar + */ + public function testFailure() + { + $deferred = new Deferred(); + + $promise = Promise\wrap($deferred->promise(), function () { + throw new \Exception('bar'); + }); + + $deferred->fail(new \Exception('foo')); + + Promise\wait($promise); + } +}