Back to Promises

UPGRADING

UPGRADING.md

3.0.09.8 KB
Original Source

Guzzle Promises Upgrade Guide

2.x to 3.0

Guzzle Promises 3.0 is a major release that raises the minimum PHP version, updates promise and collection helper signatures, adds generic PHPDoc types for static analyzers, tightens collection helper inputs, improves recursive collection behavior, and clarifies rejection inspection and late rejection callback behavior.

PHP Version and Dependencies

Guzzle Promises 3.0 requires PHP ^7.4 || ^8.0. Guzzle Promises 2.x supported PHP ^7.2.5 || ^8.0.

If your application still supports PHP 7.2 or 7.3, continue using Guzzle Promises 2.x until your minimum PHP version is raised.

Guzzle Promises 3.0 has no runtime package dependencies beyond PHP. It removes the 2.x runtime dependency on symfony/deprecation-contracts; require that package directly if your application uses it.

Optional Promise Resolution Values

PromiseInterface::resolve() now accepts an optional value. Calling resolve() without an argument fulfills the promise with null.

Custom implementations of PromiseInterface, and subclasses that override resolve() on Promise, FulfilledPromise, or RejectedPromise, must update their method signature from resolve($value): void to resolve($value = null): void.

Generic PHPDoc Types

PromiseInterface, PromisorInterface, and the built-in promise classes now include generic PHPDoc annotations for static analysis tools. The first template type represents the fulfillment value and the second represents the rejection reason. This is a static-analysis-only change and does not alter runtime behavior, but projects with stricter static analysis may see new or different diagnostics:

php
use GuzzleHttp\Promise\PromiseInterface;

/** @var PromiseInterface<string, \Throwable> */
$promise = $factory->createPromise();

$value = $promise->wait();

Code that uses unparameterized promise types continues to work and is treated as PromiseInterface<mixed, mixed>. If your project implements promise interfaces, extends promise classes, or has stricter static analysis, you may need to update your PHPDoc annotations to include the generic value and reason types. The expanded PHPDoc also preserves promise-chain fulfillment and rejection types more precisely through then() and otherwise(), and documents collection callbacks with value or reason, key, and aggregate-promise arguments so callbacks may declare only the arguments they use.

Collection Helper Inputs

Promise collection helpers now require iterable inputs. Passing a single promise or scalar value directly now throws a TypeError.

Wrap single promises or values in an array before passing them to Create::iterFor(), Each::of(), Each::ofLimit(), Each::ofLimitAll(), EachPromise, or the Utils collection helpers.

php
use GuzzleHttp\Promise\Each;

// 2.x
$promise = Each::ofLimit($singlePromise, 2);

// 3.0
$promise = Each::ofLimit([$singlePromise], 2);

IteratorAggregate inputs are now iterated via getIterator(). In 2.x an aggregate was treated as a single value and produced one result; in 3.0 its entries are consumed individually.

php
use GuzzleHttp\Promise\Utils;

$aggregate = new \ArrayObject([$promiseA, $promiseB]);

// 2.x: one result — the ArrayObject itself
// 3.0: two results — the fulfillment values of $promiseA and $promiseB
$promise = Utils::all($aggregate);

Collection Helper Signatures

Utils::all(), Utils::settle(), and Each::of() now accept trailing optional arguments. Direct calls using the 2.x argument lists continue to work, and the affected helper classes are final so subclass signatures do not need to change. Code that mirrors or reflects exact helper signatures may need to be updated.

Pass the recursive flag before the config array when using Utils::all() or Utils::settle():

php
use GuzzleHttp\Promise\Utils;

$promise = Utils::all($promises, false, ['concurrency' => 5]);
$promise = Utils::settle($promises, false, ['concurrency' => 5]);

Only concurrency is honored by these helper config arrays. Callback config keys such as fulfilled and rejected are ignored; pass callbacks to Each::of() directly or use EachPromise.

Recursive Collection Helpers

Existing Utils::all($promises, true) calls may return different results in 3.0. Recursive mode now detects dynamically-added settled promises and raw values. In 2.x, recursive mode only checked for pending promises.

If you previously worked around the lack of recursive Utils::settle() support, you can replace that workaround with the new $recursive argument:

php
use GuzzleHttp\Promise\Utils;

$promise = Utils::settle($promises, true);

When $recursive is true, collection helpers continue taking passes over the collection until no new entries are found and no visible promises remain pending. This is intended for rewindable mutable collections such as ArrayIterator. Generators are safe to pass, but they cannot be traversed again once consumed, so recursive mode degrades to a single pass; use a rewindable mutable collection when recursion needs to observe added values.

Promise Inspection

Utils::inspect() and Utils::inspectAll() now return the actual rejection reason delivered to rejection callbacks. They no longer unwrap RejectionException instances to their inner reason.

For example, a promise rejected with a RejectionException now inspects with that exception as the reason:

php
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Promise\RejectionException;
use GuzzleHttp\Promise\Utils;

$reason = new RejectionException('reason');
$result = Utils::inspect(new RejectedPromise($reason));

assert($result['reason'] === $reason);

Cancelled promises now inspect with a CancellationException reason. If you need the string reason from a RejectionException or subclass, call getReason() on the exception.

Utils::inspect() still reports wait-function failures as rejection reasons when the wait function does not settle the promise. If the wait function settles the promise and then throws, inspect() reports the settled fulfillment or rejection state; direct Promise::wait() calls continue to throw that late exception.

Late Rejection Callbacks

Rejection callbacks registered after a promise was resolved with a rejected promise are now invoked with the nested rejection reason.

php
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Promise\Utils;

$promise = new Promise();
$promise->resolve(new RejectedPromise('reason'));

$promise->then(null, function ($reason): void {
    assert($reason === 'reason');
});

Utils::queue()->run();

Non-instantiable Helper Classes

Static helper classes such as Create, Each, Is, and Utils now have private constructors. Replace any accidental instantiation with static method calls.

Native PHP Serialization of Runtime Objects

Promise, TaskQueue, EachPromise, and Coroutine no longer support native PHP serialize() or unserialize(). Persist application values instead of promise runtime state.

1.x to 2.0

Guzzle Promises 2.0 is a major release that removes deprecated APIs, raises the minimum PHP version, and adds PHP 7 parameter and return types. Applications that only use the object-oriented API should usually need small changes. Applications that call helper functions, implement package interfaces, extend package classes, or pass invalid argument types need closer review.

PHP Version and Dependencies

Guzzle Promises 2.0 requires PHP ^7.2.5 || ^8.0. Guzzle Promises 1.x supported PHP >=5.5.

PHP 7 Type Hints and Return Types

Type hints and return types were added wherever possible. Please make sure:

  • You pass values of the documented type when calling methods and functions.
  • Classes that implement PromiseInterface, PromisorInterface, or TaskQueueInterface update method signatures to remain compatible.
  • Classes that extend Guzzle Promises classes update any overridden method signatures to remain compatible.
  • Code that expected package-specific exceptions for invalid argument types may now receive PHP TypeError exceptions instead.

Soft-Final Classes

All previously non-final non-exception classes are now final or annotated with @final. If your code extends one of these classes, replace inheritance with composition or implement the relevant interface directly.

Removed Function API

The static API was introduced in 1.4.0 to mitigate problems with functions conflicting between global and local copies of the package. The function API was removed in 2.0.0, along with the Composer files autoload entry that loaded src/functions_include.php.

Replace namespaced function calls with the corresponding static methods in the GuzzleHttp\Promise namespace:

php
// Before:
use function GuzzleHttp\Promise\promise_for;

$promise = promise_for('value');

// After:
use GuzzleHttp\Promise\Create;

$promise = Create::promiseFor('value');
Original FunctionReplacement Method
queueUtils::queue
taskUtils::task
promise_forCreate::promiseFor
rejection_forCreate::rejectionFor
exception_forCreate::exceptionFor
iter_forCreate::iterFor
inspectUtils::inspect
inspect_allUtils::inspectAll
unwrapUtils::unwrap
allUtils::all
someUtils::some
anyUtils::any
settleUtils::settle
eachEach::of
each_limitEach::ofLimit
each_limit_allEach::ofLimitAll
!is_fulfilledIs::pending
is_fulfilledIs::fulfilled
is_rejectedIs::rejected
is_settledIs::settled
coroutineCoroutine::of

For the full 2.0 diff, see https://github.com/guzzle/promises/compare/1.5.3...2.0.0.