mirror of
https://github.com/danog/amp.git
synced 2024-11-30 04:29:08 +01:00
Expose combined exceptions in combinator exception
Also fix indent, escape sequences and docs
This commit is contained in:
parent
d3212d4638
commit
7046ca47e1
@ -2,4 +2,23 @@
|
||||
|
||||
namespace Amp;
|
||||
|
||||
class CombinatorException extends \RuntimeException {}
|
||||
/**
|
||||
* CombinatorException is always thrown if multiple promises are combined by combinator functions
|
||||
* and an exception is thrown.
|
||||
*/
|
||||
class CombinatorException extends \RuntimeException {
|
||||
private $exceptions;
|
||||
|
||||
/**
|
||||
* @param string $message detailed exception message
|
||||
* @param array $exceptions combined exceptions
|
||||
*/
|
||||
public function __construct($message, array $exceptions = []) {
|
||||
parent::__construct($message, 0, null);
|
||||
$this->exceptions = $exceptions;
|
||||
}
|
||||
|
||||
public function getExceptions() {
|
||||
return $this->exceptions;
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ function info() {
|
||||
*
|
||||
* If any one of the Promises fails the resulting Promise will immediately fail.
|
||||
*
|
||||
* @param array An array of promises to flatten into a single promise
|
||||
* @param array $promises An array of promises to flatten into a single promise
|
||||
* @return \Amp\Promise
|
||||
*/
|
||||
function all(array $promises) {
|
||||
@ -282,7 +282,7 @@ function all(array $promises) {
|
||||
* The individual keys in the resulting arrays are preserved from the initial Promise array
|
||||
* passed to the function for evaluation.
|
||||
*
|
||||
* @param array An array of promises to flatten into a single promise
|
||||
* @param array $promises An array of promises to flatten into a single promise
|
||||
* @return \Amp\Promise
|
||||
*/
|
||||
function some(array $promises) {
|
||||
@ -307,9 +307,8 @@ function some(array $promises) {
|
||||
}
|
||||
if (--$struct->remaining === 0) {
|
||||
if (empty($struct->results)) {
|
||||
array_unshift($struct->errors, "All promises passed to Amp\some() failed");
|
||||
$struct->promisor->fail(new CombinatorException(
|
||||
implode("\n\n", $struct->errors)
|
||||
"All promises passed to Amp\\some() failed", $struct->errors
|
||||
));
|
||||
} else {
|
||||
$struct->promisor->succeed([$struct->errors, $struct->results]);
|
||||
@ -337,7 +336,7 @@ function some(array $promises) {
|
||||
* 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 array An array of promises to flatten into a single promise
|
||||
* @param array $promises An array of promises to flatten into a single promise
|
||||
* @return \Amp\Promise
|
||||
*/
|
||||
function any(array $promises) {
|
||||
@ -381,7 +380,7 @@ function any(array $promises) {
|
||||
* Resolves with the first successful Promise value. The resulting Promise will only fail if all
|
||||
* Promise values in the group fail or if the initial Promise array is empty.
|
||||
*
|
||||
* @param array An array of promises to flatten into a single promise
|
||||
* @param array $promises An array of promises to flatten into a single promise
|
||||
* @return \Amp\Promise
|
||||
*/
|
||||
function first(array $promises) {
|
||||
@ -392,29 +391,32 @@ function first(array $promises) {
|
||||
}
|
||||
|
||||
$struct = new \StdClass;
|
||||
$struct->errors = [];
|
||||
$struct->remaining = count($promises);
|
||||
$struct->promisor = new Deferred;
|
||||
|
||||
$onResolve = function ($error, $result, $cbData) {
|
||||
$struct = $cbData;
|
||||
list($struct, $key) = $cbData;
|
||||
if ($struct->remaining === 0) {
|
||||
return;
|
||||
}
|
||||
if (empty($error)) {
|
||||
if ($error) {
|
||||
$struct->errors[$key] = $error;
|
||||
} else {
|
||||
$struct->remaining = 0;
|
||||
$struct->promisor->succeed($result);
|
||||
return;
|
||||
}
|
||||
if (--$struct->remaining === 0) {
|
||||
$struct->promisor->fail(new CombinatorException(
|
||||
"All promises failed"
|
||||
"All promises failed", $struct->errors
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
foreach ($promises as $key => $promise) {
|
||||
if ($promise instanceof Promise) {
|
||||
$promise->when($onResolve, $struct);
|
||||
$promise->when($onResolve, [$struct, $key]);
|
||||
} else {
|
||||
$struct->remaining = 0;
|
||||
$struct->promisor->succeed($promise);
|
||||
@ -426,9 +428,9 @@ function first(array $promises) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map promised deferred values using the specified functor
|
||||
* Map promised deferred values using the specified functor.
|
||||
*
|
||||
* @param array An array of promises whose values -- once resoved -- will be mapped by the functor
|
||||
* @param array $promises An array of promises whose values -- once resolved -- will be mapped by the functor
|
||||
* @param callable $functor The mapping function to apply to eventual promise results
|
||||
* @return \Amp\Promise
|
||||
*/
|
||||
@ -501,12 +503,12 @@ function map(array $promises, callable $functor) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter deferred values using the specified functor
|
||||
* Filter deferred values using the specified functor.
|
||||
*
|
||||
* If the functor returns a truthy value the resolved promise result is retained, otherwise it is
|
||||
* discarded. Array keys are retained for any results not filtered out by the functor.
|
||||
*
|
||||
* @param array An array of promises whose values -- once resoved -- will be filtered by the functor
|
||||
* @param array $promises An array of promises whose values -- once resolved -- will be filtered by the functor
|
||||
* @param callable $functor The filtering function to apply to eventual promise results
|
||||
* @return \Amp\Promise
|
||||
*/
|
||||
@ -593,7 +595,7 @@ function filter(array $promises, callable $functor = null) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pipe the promised value through the specified functor once it resolves
|
||||
* Pipe the promised value through the specified functor once it resolves.
|
||||
*
|
||||
* @param mixed $promise Any value is acceptable -- non-promises are normalized to promise form
|
||||
* @param callable $functor The functor through which to pipe the resolved promise value
|
||||
@ -717,6 +719,7 @@ function wait(Promise $promise) {
|
||||
}
|
||||
|
||||
if ($resolvedError) {
|
||||
/** @var $resolvedError \Throwable|\Exception */
|
||||
throw $resolvedError;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Amp\Test;
|
||||
|
||||
use Amp\CombinatorException;
|
||||
use Amp\NativeReactor;
|
||||
use Amp\Success;
|
||||
use Amp\Failure;
|
||||
@ -32,7 +33,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testMapReturnsEmptySuccessOnEmptyInput() {
|
||||
$promise = \Amp\map([], function () {});
|
||||
$this->assertInstanceOf("Amp\Success", $promise);
|
||||
$this->assertInstanceOf('Amp\Success', $promise);
|
||||
$error = null;
|
||||
$result = null;
|
||||
$promise->when(function ($e, $r) use (&$error, &$result) {
|
||||
@ -162,7 +163,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testFilterReturnsEmptySuccessOnEmptyInput() {
|
||||
$promise = \Amp\filter([], function () {});
|
||||
$this->assertInstanceOf("Amp\Success", $promise);
|
||||
$this->assertInstanceOf('Amp\Success', $promise);
|
||||
$error = null;
|
||||
$result = null;
|
||||
$promise->when(function ($e, $r) use (&$error, &$result) {
|
||||
@ -301,6 +302,18 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertSame(1, $invoked);
|
||||
}
|
||||
|
||||
public function testSomeResolutionWhenAllPromisesFail() {
|
||||
$ex1 = new \RuntimeException("1");
|
||||
$ex2 = new \RuntimeException("2");
|
||||
$promises = [new Failure($ex1), new Failure($ex2)];
|
||||
\Amp\some($promises)->when(function ($e, $r) use ($ex1, $ex2) {
|
||||
$this->assertNull($r);
|
||||
$this->assertInstanceOf(CombinatorException::class, $e);
|
||||
$this->assertSame($e->getExceptions()[0], $ex1);
|
||||
$this->assertSame($e->getExceptions()[1], $ex2);
|
||||
});
|
||||
}
|
||||
|
||||
public function testAllResolutionWhenNoPromiseInstancesCombined() {
|
||||
$promises = [null, 1, 2, true];
|
||||
\Amp\all($promises)->when(function ($e, $r) {
|
||||
@ -338,7 +351,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testAnyReturnsImmediatelyOnEmptyPromiseArray() {
|
||||
$promise = \Amp\any([]);
|
||||
$this->assertInstanceOf("Amp\Success", $promise);
|
||||
$this->assertInstanceOf('Amp\Success', $promise);
|
||||
$error = null;
|
||||
$result = null;
|
||||
$promise->when(function ($e, $r) use (&$error, &$result) {
|
||||
@ -358,7 +371,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testAllReturnsImmediatelyOnEmptyPromiseArray() {
|
||||
$promise = \Amp\all([]);
|
||||
$this->assertInstanceOf("Amp\Success", $promise);
|
||||
$this->assertInstanceOf('Amp\Success', $promise);
|
||||
$error = null;
|
||||
$result = null;
|
||||
$promise->when(function ($e, $r) use (&$error, &$result) {
|
||||
@ -391,7 +404,8 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
'r2' => new Failure($exception),
|
||||
'r3' => new Success(40),
|
||||
])->when(function ($error, $result) use ($exception) {
|
||||
list($errors, $results) = (yield \Amp\some($promises));
|
||||
$this->assertNull($error);
|
||||
list($errors, $results) = $result;
|
||||
$this->assertSame(['r2' => $exception], $errors);
|
||||
$this->assertSame(['r1' => 42, 'r3' => 40], $results);
|
||||
});
|
||||
@ -399,7 +413,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testSomeFailsImmediatelyOnEmptyPromiseArrayInput() {
|
||||
$promise = \Amp\some([]);
|
||||
$this->assertInstanceOf("Amp\Failure", $promise);
|
||||
$this->assertInstanceOf('Amp\Failure', $promise);
|
||||
$error = null;
|
||||
$result = null;
|
||||
$promise->when(function ($e, $r) use (&$error, &$result) {
|
||||
@ -407,7 +421,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
$result = $r;
|
||||
});
|
||||
$this->assertNull($result);
|
||||
$this->assertInstanceOf("\LogicException", $error);
|
||||
$this->assertInstanceOf('\LogicException', $error);
|
||||
$this->assertSame("No promises or values provided for resolution", $error->getMessage());
|
||||
}
|
||||
|
||||
@ -425,7 +439,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testFirstFailsImmediatelyOnEmptyPromiseArrayInput() {
|
||||
$promise = \Amp\first([]);
|
||||
$this->assertInstanceOf("Amp\Failure", $promise);
|
||||
$this->assertInstanceOf('Amp\Failure', $promise);
|
||||
$error = null;
|
||||
$result = null;
|
||||
$promise->when(function ($e, $r) use (&$error, &$result) {
|
||||
@ -433,7 +447,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
$result = $r;
|
||||
});
|
||||
$this->assertNull($result);
|
||||
$this->assertInstanceOf("\LogicException", $error);
|
||||
$this->assertInstanceOf('\LogicException', $error);
|
||||
$this->assertSame("No promises or values provided", $error->getMessage());
|
||||
}
|
||||
|
||||
@ -461,7 +475,7 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$promises = [$p1->promise(), $p2->promise(), $p3->promise()];
|
||||
$allPromise = \Amp\all($promises);
|
||||
$allPromise->when("\Amp\stop");
|
||||
$allPromise->when('\Amp\stop');
|
||||
|
||||
$result = (yield \Amp\first($promises));
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user