diff --git a/src/Internal/Queue.php b/src/Internal/Queue.php index f8468b53..70f85817 100644 --- a/src/Internal/Queue.php +++ b/src/Internal/Queue.php @@ -19,11 +19,10 @@ public function enqueue(callable $task): void private function drain(): void { for ($i = \key($this->queue); isset($this->queue[$i]); $i++) { - try { - ($this->queue[$i])(); - } finally { - unset($this->queue[$i]); - } + $task = $this->queue[$i]; + unset($this->queue[$i]); + + $task(); } $this->queue = []; diff --git a/tests/Internal/QueueTest.php b/tests/Internal/QueueTest.php index ee26a003..51ffedc1 100644 --- a/tests/Internal/QueueTest.php +++ b/tests/Internal/QueueTest.php @@ -30,6 +30,27 @@ public function executesNestedEnqueuedTasks() $queue->enqueue($task); } + /** + * @test + * @requires PHP 8.1 + */ + public function executesFollowingTasksIfPriorTaskSuspendsFiber() + { + $queue = new Queue(); + + $fiber = new \Fiber(function () use ($queue) { + $queue->enqueue(function () { + \Fiber::suspend(2); + }); + return 1; + }); + + $ret = $fiber->start(); + $this->assertEquals(2, $ret); + + $queue->enqueue($this->expectCallableOnce()); + } + /** * @test */ diff --git a/tests/PromiseTest/PromiseFulfilledTestTrait.php b/tests/PromiseTest/PromiseFulfilledTestTrait.php index ec236147..331c8d96 100644 --- a/tests/PromiseTest/PromiseFulfilledTestTrait.php +++ b/tests/PromiseTest/PromiseFulfilledTestTrait.php @@ -184,6 +184,33 @@ public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows() ); } + /** + * @test + * @requires PHP 8.1 + */ + public function thenShouldContinueToExecuteCallbacksWhenPriorCallbackSuspendsFiber() + { + $adapter = $this->getPromiseTestAdapter(); + $adapter->resolve(42); + + $fiber = new \Fiber(function () use ($adapter) { + $adapter->promise()->then(function (int $value) { + \Fiber::suspend($value); + }); + }); + + $ret = $fiber->start(); + $this->assertEquals(42, $ret); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(42)); + + $adapter->promise()->then($mock); + } + /** @test */ public function cancelShouldReturnNullForFulfilledPromise() {