PHPackages                             ehough/promises - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. ehough/promises

AbandonedArchivedLibrary[Queues &amp; Workers](/categories/queues)

ehough/promises
===============

PHP 5.3-compatible fork of guzzle/promises

v1.3.1(9y ago)25.8k2MITPHPPHP &gt;=5.3.29

Since Jun 14Pushed 9y ago1 watchersCompare

[ Source](https://github.com/ehough/promises)[ Packagist](https://packagist.org/packages/ehough/promises)[ RSS](/packages/ehough-promises/feed)WikiDiscussions develop Synced 1mo ago

READMEChangelogDependencies (2)Versions (6)Used By (2)

ehough/promises
===============

[](#ehoughpromises)

[![Build Status](https://camo.githubusercontent.com/80f8f03b527cd3ba73e48681c3491b1d3da749bc8a12b0bbe254f6117f3150d9/68747470733a2f2f7472617669732d63692e6f72672f65686f7567682f70726f6d697365732e7376673f6272616e63683d646576656c6f70)](https://travis-ci.org/ehough/promises)[![Latest Stable Version](https://camo.githubusercontent.com/25889292cdcc7756cdbdb67c3f28547f17f6cf5901f6655150335267a8a4a0b6/68747470733a2f2f706f7365722e707567782e6f72672f65686f7567682f70726f6d697365732f762f737461626c65)](https://packagist.org/packages/ehough/promises)[![License](https://camo.githubusercontent.com/2debb935482be277c5befaca04c9578329a0f2f0bcc205c059b6c2d8b9766abf/68747470733a2f2f706f7365722e707567782e6f72672f65686f7567682f70726f6d697365732f6c6963656e7365)](https://packagist.org/packages/ehough/promises)

A PHP 5.3-compatible fork of [`guzzle/promises`](https://github.com/guzzle/promises).

Why?
====

[](#why)

Sadly, [60%](https://w3techs.com/technologies/details/pl-php/5/all) of all PHP web servers still run PHP 5.4 and lower, but [`guzzle/psr7`](https://github.com/guzzle/promises) needs PHP 5.5 or higher. This fork makes `guzzle/promises` compatible with PHP 5.3.29 through 7.1.

How to Use This Fork
====================

[](#how-to-use-this-fork)

Usage is identical to [`guzzle/promises`](https://github.com/guzzle/promises), except that the code in this library is namespaced under `Hough\Promise` instead of `GuzzleHttp\Promise`.

---

[Promises/A+](https://promisesaplus.com/) implementation that handles promise chaining and resolution iteratively, allowing for "infinite" promise chaining while keeping the stack size constant. Read [this blog post](https://blog.domenic.me/youre-missing-the-point-of-promises/)for a general introduction to promises.

- [Features](#features)
- [Quick start](#quick-start)
- [Synchronous wait](#synchronous-wait)
- [Cancellation](#cancellation)
- [API](#api)
    - [Promise](#promise)
    - [FulfilledPromise](#fulfilledpromise)
    - [RejectedPromise](#rejectedpromise)
- [Promise interop](#promise-interop)
- [Implementation notes](#implementation-notes)

Features
========

[](#features)

- [Promises/A+](https://promisesaplus.com/) implementation.
- Promise resolution and chaining is handled iteratively, allowing for "infinite" promise chaining.
- Promises have a synchronous `wait` method.
- Promises can be cancelled.
- Works with any object that has a `then` function.
- C# style async/await coroutine promises using `Hough\Promise\coroutine()`.

Quick start
===========

[](#quick-start)

A *promise* represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its `then` method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled.

Callbacks
---------

[](#callbacks)

Callbacks are registered with the `then` method by providing an optional `$onFulfilled` followed by an optional `$onRejected` function.

```
use Hough\Promise\Promise;

$promise = new Promise();
$promise->then(
    // $onFulfilled
    function ($value) {
        echo 'The promise was fulfilled.';
    },
    // $onRejected
    function ($reason) {
        echo 'The promise was rejected.';
    }
);
```

*Resolving* a promise means that you either fulfill a promise with a *value* or reject a promise with a *reason*. Resolving a promises triggers callbacks registered with the promises's `then` method. These callbacks are triggered only once and in the order in which they were added.

Resolving a promise
-------------------

[](#resolving-a-promise)

Promises are fulfilled using the `resolve($value)` method. Resolving a promise with any value other than a `Hough\Promise\RejectedPromise` will trigger all of the onFulfilled callbacks (resolving a promise with a rejected promise will reject the promise and trigger the `$onRejected` callbacks).

```
use Hough\Promise\Promise;

$promise = new Promise();
$promise
    ->then(function ($value) {
        // Return a value and don't break the chain
        return "Hello, " . $value;
    })
    // This then is executed after the first then and receives the value
    // returned from the first then.
    ->then(function ($value) {
        echo $value;
    });

// Resolving the promise triggers the $onFulfilled callbacks and outputs
// "Hello, reader".
$promise->resolve('reader.');
```

Promise forwarding
------------------

[](#promise-forwarding)

Promises can be chained one after the other. Each then in the chain is a new promise. The return value of a promise is what's forwarded to the next promise in the chain. Returning a promise in a `then` callback will cause the subsequent promises in the chain to only be fulfilled when the returned promise has been fulfilled. The next promise in the chain will be invoked with the resolved value of the promise.

```
use Hough\Promise\Promise;

$promise = new Promise();
$nextPromise = new Promise();

$promise
    ->then(function ($value) use ($nextPromise) {
        echo $value;
        return $nextPromise;
    })
    ->then(function ($value) {
        echo $value;
    });

// Triggers the first callback and outputs "A"
$promise->resolve('A');
// Triggers the second callback and outputs "B"
$nextPromise->resolve('B');
```

Promise rejection
-----------------

[](#promise-rejection)

When a promise is rejected, the `$onRejected` callbacks are invoked with the rejection reason.

```
use Hough\Promise\Promise;

$promise = new Promise();
$promise->then(null, function ($reason) {
    echo $reason;
});

$promise->reject('Error!');
// Outputs "Error!"
```

Rejection forwarding
--------------------

[](#rejection-forwarding)

If an exception is thrown in an `$onRejected` callback, subsequent `$onRejected` callbacks are invoked with the thrown exception as the reason.

```
use Hough\Promise\Promise;

$promise = new Promise();
$promise->then(null, function ($reason) {
    throw new \Exception($reason);
})->then(null, function ($reason) {
    assert($reason->getMessage() === 'Error!');
});

$promise->reject('Error!');
```

You can also forward a rejection down the promise chain by returning a `Hough\Promise\RejectedPromise` in either an `$onFulfilled` or `$onRejected` callback.

```
use Hough\Promise\Promise;
use Hough\Promise\RejectedPromise;

$promise = new Promise();
$promise->then(null, function ($reason) {
    return new RejectedPromise($reason);
})->then(null, function ($reason) {
    assert($reason === 'Error!');
});

$promise->reject('Error!');
```

If an exception is not thrown in a `$onRejected` callback and the callback does not return a rejected promise, downstream `$onFulfilled` callbacks are invoked using the value returned from the `$onRejected` callback.

```
use Hough\Promise\Promise;
use Hough\Promise\RejectedPromise;

$promise = new Promise();
$promise
    ->then(null, function ($reason) {
        return "It's ok";
    })
    ->then(function ($value) {
        assert($value === "It's ok");
    });

$promise->reject('Error!');
```

Synchronous wait
================

[](#synchronous-wait)

You can synchronously force promises to complete using a promise's `wait`method. When creating a promise, you can provide a wait function that is used to synchronously force a promise to complete. When a wait function is invoked it is expected to deliver a value to the promise or reject the promise. If the wait function does not deliver a value, then an exception is thrown. The wait function provided to a promise constructor is invoked when the `wait` function of the promise is called.

```
$promise = new Promise(function () use (&$promise) {
    $promise->resolve('foo');
});

// Calling wait will return the value of the promise.
echo $promise->wait(); // outputs "foo"
```

If an exception is encountered while invoking the wait function of a promise, the promise is rejected with the exception and the exception is thrown.

```
$promise = new Promise(function () use (&$promise) {
    throw new \Exception('foo');
});

$promise->wait(); // throws the exception.
```

Calling `wait` on a promise that has been fulfilled will not trigger the wait function. It will simply return the previously resolved value.

```
$promise = new Promise(function () { die('this is not called!'); });
$promise->resolve('foo');
echo $promise->wait(); // outputs "foo"
```

Calling `wait` on a promise that has been rejected will throw an exception. If the rejection reason is an instance of `\Exception` the reason is thrown. Otherwise, a `Hough\Promise\RejectionException` is thrown and the reason can be obtained by calling the `getReason` method of the exception.

```
$promise = new Promise();
$promise->reject('foo');
$promise->wait();
```

> PHP Fatal error: Uncaught exception 'Hough\\Promise\\RejectionException' with message 'The promise was rejected with value: foo'

Unwrapping a promise
--------------------

[](#unwrapping-a-promise)

When synchronously waiting on a promise, you are joining the state of the promise into the current state of execution (i.e., return the value of the promise if it was fulfilled or throw an exception if it was rejected). This is called "unwrapping" the promise. Waiting on a promise will by default unwrap the promise state.

You can force a promise to resolve and *not* unwrap the state of the promise by passing `false` to the first argument of the `wait` function:

```
$promise = new Promise();
$promise->reject('foo');
// This will not throw an exception. It simply ensures the promise has
// been resolved.
$promise->wait(false);
```

When unwrapping a promise, the resolved value of the promise will be waited upon until the unwrapped value is not a promise. This means that if you resolve promise A with a promise B and unwrap promise A, the value returned by the wait function will be the value delivered to promise B.

**Note**: when you do not unwrap the promise, no value is returned.

Cancellation
============

[](#cancellation)

You can cancel a promise that has not yet been fulfilled using the `cancel()`method of a promise. When creating a promise you can provide an optional cancel function that when invoked cancels the action of computing a resolution of the promise.

API
===

[](#api)

Promise
-------

[](#promise)

When creating a promise object, you can provide an optional `$waitFn` and `$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is expected to resolve the promise. `$cancelFn` is a function with no arguments that is expected to cancel the computation of a promise. It is invoked when the `cancel()` method of a promise is called.

```
use Hough\Promise\Promise;

$promise = new Promise(
    function () use (&$promise) {
        $promise->resolve('waited');
    },
    function () {
        // do something that will cancel the promise computation (e.g., close
        // a socket, cancel a database query, etc...)
    }
);

assert('waited' === $promise->wait());
```

A promise has the following methods:

- `then(callable $onFulfilled, callable $onRejected) : PromiseInterface`

    Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler.
- `otherwise(callable $onRejected) : PromiseInterface`

    Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled.
- `wait($unwrap = true) : mixed`

    Synchronously waits on the promise to complete.

    `$unwrap` controls whether or not the value of the promise is returned for a fulfilled promise or if an exception is thrown if the promise is rejected. This is set to `true` by default.
- `cancel()`

    Attempts to cancel the promise if possible. The promise being cancelled and the parent most ancestor that has not yet been resolved will also be cancelled. Any promises waiting on the cancelled promise to resolve will also be cancelled.
- `getState() : string`

    Returns the state of the promise. One of `pending`, `fulfilled`, or `rejected`.
- `resolve($value)`

    Fulfills the promise with the given `$value`.
- `reject($reason)`

    Rejects the promise with the given `$reason`.

FulfilledPromise
----------------

[](#fulfilledpromise)

A fulfilled promise can be created to represent a promise that has been fulfilled.

```
use Hough\Promise\FulfilledPromise;

$promise = new FulfilledPromise('value');

// Fulfilled callbacks are immediately invoked.
$promise->then(function ($value) {
    echo $value;
});
```

RejectedPromise
---------------

[](#rejectedpromise)

A rejected promise can be created to represent a promise that has been rejected.

```
use Hough\Promise\RejectedPromise;

$promise = new RejectedPromise('Error');

// Rejected callbacks are immediately invoked.
$promise->then(null, function ($reason) {
    echo $reason;
});
```

Promise interop
===============

[](#promise-interop)

This library works with foreign promises that have a `then` method. This means you can use Guzzle promises with [React promises](https://github.com/reactphp/promise)for example. When a foreign promise is returned inside of a then method callback, promise resolution will occur recursively.

```
// Create a React promise
$deferred = new React\Promise\Deferred();
$reactPromise = $deferred->promise();

// Create a Guzzle promise that is fulfilled with a React promise.
$guzzlePromise = new \Hough\Promise\Promise();
$guzzlePromise->then(function ($value) use ($reactPromise) {
    // Do something something with the value...
    // Return the React promise
    return $reactPromise;
});
```

Please note that wait and cancel chaining is no longer possible when forwarding a foreign promise. You will need to wrap a third-party promise with a Guzzle promise in order to utilize wait and cancel functions with foreign promises.

Event Loop Integration
----------------------

[](#event-loop-integration)

In order to keep the stack size constant, Guzzle promises are resolved asynchronously using a task queue. When waiting on promises synchronously, the task queue will be automatically run to ensure that the blocking promise and any forwarded promises are resolved. When using promises asynchronously in an event loop, you will need to run the task queue on each tick of the loop. If you do not run the task queue, then promises will not be resolved.

You can run the task queue using the `run()` method of the global task queue instance.

```
// Get the global task queue
$queue = \Hough\Promise\queue();
$queue->run();
```

For example, you could use Guzzle promises with React using a periodic timer:

```
$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(0, [$queue, 'run']);
```

*TODO*: Perhaps adding a `futureTick()` on each tick would be faster?

Implementation notes
====================

[](#implementation-notes)

Promise resolution and chaining is handled iteratively
------------------------------------------------------

[](#promise-resolution-and-chaining-is-handled-iteratively)

By shuffling pending handlers from one owner to another, promises are resolved iteratively, allowing for "infinite" then chaining.

```
