Add public resolve/reject to Promise and fix all() implementation

- Add public resolve() and reject() methods to Promise class
- Create combined promise without executor (no coroutine spawned)
- Use direct resolve/reject calls instead of captured callbacks
- This ensures the promise can be settled regardless of coroutine timing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jake Barnby
2026-01-21 20:56:28 +13:00
parent 7b9970af9c
commit cd75f17815
2 changed files with 41 additions and 14 deletions
@@ -44,26 +44,21 @@ class Swoole extends Adapter
return $this->createFulfilled([]);
}
// Create the combined promise without an executor (won't start a coroutine)
$combinedPromise = new SwoolePromise();
// Shared state across callbacks
$count = 0;
$result = [];
$rejected = false;
$resolveCallback = null;
$rejectCallback = null;
$resolveAllWhenFinished = function () use (&$count, $total, &$result, &$rejected, &$resolveCallback): void {
if (!$rejected && $count === $total && $resolveCallback !== null) {
$resolveAllWhenFinished = static function () use (&$count, $total, &$result, &$rejected, $combinedPromise): void {
if (!$rejected && $count === $total) {
\ksort($result);
$resolveCallback($result);
$combinedPromise->resolve($result);
}
};
// Create the combined promise - the executor captures the resolve/reject callbacks
$combinedPromise = new SwoolePromise(function ($resolve, $reject) use (&$resolveCallback, &$rejectCallback) {
$resolveCallback = $resolve;
$rejectCallback = $reject;
});
// Register then callbacks on each input promise
foreach ($promisesOrValues as $index => $promiseOrValue) {
if ($promiseOrValue instanceof GQLPromise) {
@@ -74,10 +69,10 @@ class Swoole extends Adapter
++$count;
$resolveAllWhenFinished();
},
static function ($error) use (&$rejected, &$rejectCallback): void {
if (!$rejected && $rejectCallback !== null) {
static function ($error) use (&$rejected, $combinedPromise): void {
if (!$rejected) {
$rejected = true;
$rejectCallback($error);
$combinedPromise->reject($error);
}
}
);
+32
View File
@@ -201,4 +201,36 @@ abstract class Promise
{
return $this->result;
}
/**
* Resolve the promise with a value
*
* @param mixed $value
* @return self
*/
public function resolve(mixed $value): self
{
if ($this->state !== self::STATE_PENDING) {
return $this;
}
$this->setResult($value);
$this->setState(self::STATE_FULFILLED);
return $this;
}
/**
* Reject the promise with a reason
*
* @param mixed $reason
* @return self
*/
public function reject(mixed $reason): self
{
if ($this->state !== self::STATE_PENDING) {
return $this;
}
$this->setResult($reason);
$this->setState(self::STATE_REJECTED);
return $this;
}
}