Fix Promise::all() to handle mixed values and promises

The graphql-php executor passes both promises and plain values to
the PromiseAdapter::all() method. Updated SwoolePromise::all() to
properly handle plain values by storing them directly without
attempting to call ->then() on them.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jake Barnby
2026-01-21 18:36:40 +13:00
co-authored by Claude Opus 4.5
parent 762be367e1
commit a70d67810e
+47 -18
View File
@@ -28,33 +28,62 @@ class Swoole extends Promise
/**
* Returns a promise that completes when all passed in promises complete.
*
* @param iterable|Swoole[] $promises
* @param iterable $promisesOrValues Array of promises and/or plain values
* @return Promise
*/
public static function all(iterable $promises): Promise
public static function all(iterable $promisesOrValues): Promise
{
return self::create(function (callable $resolve, callable $reject) use ($promises) {
$ticks = count($promises);
return self::create(function (callable $resolve, callable $reject) use ($promisesOrValues) {
$result = [];
$error = null;
$channel = new Channel($ticks);
$promiseCount = 0;
$key = 0;
foreach ($promises as $promise) {
$promise->then(function ($value) use ($key, &$result, $channel) {
$result[$key] = $value;
$channel->push(true);
return $value;
}, function ($err) use ($channel, &$error) {
$channel->push(true);
if ($error === null) {
$error = $err;
}
});
// First pass: count promises and store plain values
$promiseKeys = [];
foreach ($promisesOrValues as $promiseOrValue) {
if ($promiseOrValue instanceof Promise) {
$promiseKeys[] = $key;
$promiseCount++;
} else {
$result[$key] = $promiseOrValue;
}
$key++;
}
while ($ticks--) {
// If no promises, resolve immediately
if ($promiseCount === 0) {
\ksort($result);
$resolve($result);
return;
}
$channel = new Channel($promiseCount);
$key = 0;
foreach ($promisesOrValues as $promiseOrValue) {
if ($promiseOrValue instanceof Promise) {
$currentKey = $key;
$promiseOrValue->then(
function ($value) use ($currentKey, &$result, $channel) {
$result[$currentKey] = $value;
$channel->push(true);
return $value;
},
function ($err) use ($channel, &$error) {
$channel->push(true);
if ($error === null) {
$error = $err;
}
}
);
}
$key++;
}
// Wait for all promises
$remaining = $promiseCount;
while ($remaining-- > 0) {
$channel->pop();
}
$channel->close();