php-standard-library/promise
Lightweight PHP promise implementation for composing and coordinating async-style workflows. Create, resolve, reject, and chain promises with then/catch-style handlers, useful for deferred results, task pipelines, and bridging callback-based APIs into a cleaner flow.
Installation:
composer require php-standard-library/promise
Add to composer.json under require if not using Composer globally.
First Use Case:
Replace a nested callback with a Promise chain for a simple async operation (e.g., HTTP request, DB query):
use PhpStandardLibrary\Promise\Promise;
$promise = new Promise(function ($resolve, $reject) {
// Simulate async work (e.g., Guzzle HTTP request)
$response = file_get_contents('https://api.example.com/data');
if ($response === false) {
$reject(new RuntimeException('Request failed'));
} else {
$resolve(json_decode($response, true));
}
});
$promise->then(
function ($data) {
// Handle success
return $data['result'];
}
)->catch(
function (Throwable $e) {
// Handle error
error_log($e->getMessage());
}
);
Where to Look First:
Promise class: Core class for creating and chaining promises.Promise\all()/Promise\race(): Static combinators for orchestrating multiple promises.Promise\defer(): Helper for creating deferred promises (resolved/rejected later).tests/ or examples/ directories (if provided).Deferred Resolution:
Use Promise\defer() to create a promise resolved/rejected later (e.g., in event handlers):
$deferred = Promise\defer();
// Later, in an event listener:
$deferred->resolve($data);
// Or:
$deferred->reject(new Exception('Failed'));
Chaining Async Operations:
Chain .then() for sequential async work (e.g., fetch → process → save):
$promise
->then(fn($data) => $this->processData($data))
->then(fn($processed) => $this->saveToDb($processed));
Parallel Execution with all():
Run multiple promises concurrently and wait for all to complete:
$promises = [
$this->fetchUserData($userId),
$this->fetchOrderHistory($userId),
];
Promise\all($promises)->then(function ($results) {
$userData = $results[0];
$orderHistory = $results[1];
// Combine results...
});
Error Handling:
Use .catch() for global error handling or .then() with rejection checks:
$promise->then(
fn($data) => $data,
fn(Throwable $e) => error_log($e)
);
Integration with Laravel:
$job = Bus::dispatch(new ProcessDataJob($data));
Promise\fromCallable([$job, 'handle'])
->then(fn() => $this->notifyUser());
$promise = new Promise(function ($resolve) use ($client) {
$client->getAsync('...')->then(fn($response) => $resolve($response->getBody()));
});
Custom Promise Creators: Extend the library by creating helper methods for your domain:
function fetchWithRetry($url, int $retries = 3): Promise {
return new Promise(function ($resolve, $reject) use ($url, $retries) {
// Retry logic...
});
}
No Event Loop:
Promise::wait()). Use Promise\all() or Promise\race() to block until completion.Memory Leaks:
.finally() to clean up:
$promise->finally(fn() => $this->cleanup());
Callback Order:
.then() handlers run in registration order, not execution order. Avoid relying on order for side effects.Rejection Handling:
.catch() or handle rejections explicitly:
$promise->then(fn($data) => $data)->catch(fn($e) => null);
Thread Safety:
State Inspection:
Use Promise::isPending(), Promise::isFulfilled(), or Promise::isRejected() to debug stuck promises:
if ($promise->isPending()) {
error_log('Promise is still pending!');
}
Stack Traces: Wrap rejections in exceptions with stack traces for debugging:
$promise->catch(function (Throwable $e) {
throw new RuntimeException('Failed to process', 0, $e);
});
Logging: Log promise states for observability:
$promise->then(fn() => logger()->info('Resolved!'))
->catch(fn($e) => logger()->error($e));
Compose with Laravel:
Promise with Laravel’s Bus or Queue for async workflows:
$job = Bus::dispatch(new AsyncJob());
Promise\fromCallable([$job, 'handle'])->then(...);
Type Safety: Use PHP 8’s return types for better IDE support:
function fetchData(): Promise {
return new Promise(fn($resolve) => $resolve(['data']));
}
Testing:
Mock promises in tests with Promise\resolve() or Promise\reject():
$mockPromise = Promise\resolve(['test']);
$this->app->instance(Promise::class, $mockPromise);
Performance:
Promise\all() over sequential .then() chains for parallel tasks.foreach).Extension Points:
PhpStandardLibrary\Promise\PromiseInterface for custom promise types.Promise to add domain-specific methods (e.g., Promise::retry()).How can I help you explore Laravel packages today?