Skip to content

Http client async promises are mutable #60196

@rhysemmerson

Description

@rhysemmerson

Laravel Version

13.9.0

PHP Version

8.3

Database Driver & Version

No response

Description

When using the async feature of the http client facade without pool, the promises that are returned are mutable which to me is quite unexpected since guzzle promises are immutable and the promises returned are typed as the guzzle PromiseInterface.

The comment on PromiseInterface::then even state that it returns a new instance

/**
 * Appends fulfillment and rejection handlers to the promise, and returns
 * a new promise resolving to the return value of the called handler.
 *
 * @param callable $onFulfilled Invoked when the promise fulfills.
 * @param callable $onRejected  Invoked when the promise is rejected.
 */
public function then(
    ?callable $onFulfilled = null,
    ?callable $onRejected = null
): PromiseInterface;

In this example $pomise1, $promise2 and $promise3 all point to the same promise since the then function returns $this.

Artisan::command('promises', function () {
    $promise1 = Http::async()
        ->get('https://www.laravel.com')
        ->then(fn (Response $response) => $response->status());
    $promise2 = $promise1->then(fn ($records) => 'one');
    $promise3 = $promise2->then(fn ($records) => 'two');

    $result1 = $promise1->wait();
    $result2 = $promise2->wait();
    $result3 = $promise3->wait();

    dump($result1, $result2, $result3);
});

The output is:

"two"
"two"
"two"

The expected output would be:

200
"one"
"two"

Steps To Reproduce

Artisan::command('promises', function () {
    $promise1 = Http::async()->get('https://www.laravel.com');
    $promise2 = $promise1->then(fn ($records) => ['one', 'two']);
    $promise3 = $promise2->then(fn ($records) => ['three', 'four']);

    $result1 = $promise1->wait();
    $result2 = $promise2->wait();
    $result3 = $promise3->wait();

    dump($result1, $result2, $result3);
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions