diff --git a/src/functions.php b/src/functions.php index ac350e5..cbd19fb 100644 --- a/src/functions.php +++ b/src/functions.php @@ -246,6 +246,25 @@ function (mixed $throwable) use (&$rejected, &$rejectedThrowable, &$fiber): void $throwable = new \UnexpectedValueException( 'Promise rejected with unexpected value of type ' . (is_object($throwable) ? get_class($throwable) : gettype($throwable)) ); + + // avoid garbage references by replacing all closures in call stack. + // what a lovely piece of code! + $r = new \ReflectionProperty('Exception', 'trace'); + $trace = $r->getValue($throwable); + + // Exception trace arguments only available when zend.exception_ignore_args is not set + // @codeCoverageIgnoreStart + foreach ($trace as $ti => $one) { + if (isset($one['args'])) { + foreach ($one['args'] as $ai => $arg) { + if ($arg instanceof \Closure) { + $trace[$ti]['args'][$ai] = 'Object(' . \get_class($arg) . ')'; + } + } + } + } + // @codeCoverageIgnoreEnd + $r->setValue($throwable, $trace); } if ($fiber === null) { diff --git a/tests/AwaitTest.php b/tests/AwaitTest.php index 1bb61e0..2bf1314 100644 --- a/tests/AwaitTest.php +++ b/tests/AwaitTest.php @@ -53,9 +53,15 @@ public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWith $reject(null); }); - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessage('Promise rejected with unexpected value of type NULL'); - $await($promise); + try { + $await($promise); + } catch (\UnexpectedValueException $exception) { + $this->assertInstanceOf(\UnexpectedValueException::class, $exception); + $this->assertEquals('Promise rejected with unexpected value of type NULL', $exception->getMessage()); + $this->assertEquals(0, $exception->getCode()); + $this->assertNull($exception->getPrevious()); + $this->assertNotEquals('', $exception->getTraceAsString()); + } } /**