1=======
2Futures
3=======
4
5Futures represent a computation that may have not yet completed. RingPHP
6uses hybrid of futures and promises to provide a consistent API that can be
7used for both blocking and non-blocking consumers.
8
9Promises
10--------
11
12You can get the result of a future when it is ready using the promise interface
13of a future. Futures expose a promise API via a ``then()`` method that utilizes
14`React's promise library <https://github.com/reactphp/promise>`_. You should
15use this API when you do not wish to block.
16
17.. code-block:: php
18
19    use GuzzleHttp\Ring\Client\CurlMultiHandler;
20
21    $request = [
22        'http_method' => 'GET',
23        'uri'         => '/',
24        'headers'     => ['host' => ['httpbin.org']]
25    ];
26
27    $response = $handler($request);
28
29    // Use the then() method to use the promise API of the future.
30    $response->then(function ($response) {
31        echo $response['status'];
32    });
33
34You can get the promise used by a future, an instance of
35``React\Promise\PromiseInterface``, by calling the ``promise()`` method.
36
37.. code-block:: php
38
39    $response = $handler($request);
40    $promise = $response->promise();
41    $promise->then(function ($response) {
42        echo $response['status'];
43    });
44
45This promise value can be used with React's
46`aggregate promise functions <https://github.com/reactphp/promise#functions>`_.
47
48Waiting
49-------
50
51You can wait on a future to complete and retrieve the value, or *dereference*
52the future, using the ``wait()`` method. Calling the ``wait()`` method of a
53future will block until the result is available. The result is then returned or
54an exception is thrown if and exception was encountered while waiting on the
55the result. Subsequent calls to dereference a future will return the previously
56completed result or throw the previously encountered exception. Futures can be
57cancelled, which stops the computation if possible.
58
59.. code-block:: php
60
61    use GuzzleHttp\Ring\Client\CurlMultiHandler;
62
63    $response = $handler([
64        'http_method' => 'GET',
65        'uri'         => '/',
66        'headers'     => ['host' => ['httpbin.org']]
67    ]);
68
69    // You can explicitly call block to wait on a result.
70    $realizedResponse = $response->wait();
71
72    // Future responses can be used like a regular PHP array.
73    echo $response['status'];
74
75In addition to explicitly calling the ``wait()`` function, using a future like
76a normal value will implicitly trigger the ``wait()`` function.
77
78Future Responses
79----------------
80
81RingPHP uses futures to return asynchronous responses immediately. Client
82handlers always return future responses that implement
83``GuzzleHttp\Ring\Future\ArrayFutureInterface``. These future responses act
84just like normal PHP associative arrays for blocking access and provide a
85promise interface for non-blocking access.
86
87.. code-block:: php
88
89    use GuzzleHttp\Ring\Client\CurlMultiHandler;
90
91    $handler = new CurlMultiHandler();
92
93    $request = [
94        'http_method'  => 'GET',
95        'uri'          => '/',
96        'headers'      => ['Host' => ['www.google.com']]
97    ];
98
99    $response = $handler($request);
100
101    // Use the promise API for non-blocking access to the response. The actual
102    // response value will be delivered to the promise.
103    $response->then(function ($response) {
104        echo $response['status'];
105    });
106
107    // You can wait (block) until the future is completed.
108    $response->wait();
109
110    // This will implicitly call wait(), and will block too!
111    $response['status'];
112
113.. important::
114
115    Futures that are not completed by the time the underlying handler is
116    destructed will be completed when the handler is shutting down.
117
118Cancelling
119----------
120
121Futures can be cancelled if they have not already been dereferenced.
122
123RingPHP futures are typically implemented with the
124``GuzzleHttp\Ring\Future\BaseFutureTrait``. This trait provides the cancellation
125functionality that should be common to most implementations. Cancelling a
126future response will try to prevent the request from sending over the wire.
127
128When a future is cancelled, the cancellation function is invoked and performs
129the actual work needed to cancel the request from sending if possible
130(e.g., telling an event loop to stop sending a request or to close a socket).
131If no cancellation function is provided, then a request cannot be cancelled. If
132a cancel function is provided, then it should accept the future as an argument
133and return true if the future was successfully cancelled or false if it could
134not be cancelled.
135
136Wrapping an existing Promise
137----------------------------
138
139You can easily create a future from any existing promise using the
140``GuzzleHttp\Ring\Future\FutureValue`` class. This class's constructor
141accepts a promise as the first argument, a wait function as the second
142argument, and a cancellation function as the third argument. The dereference
143function is used to force the promise to resolve (for example, manually ticking
144an event loop). The cancel function is optional and is used to tell the thing
145that created the promise that it can stop computing the result (for example,
146telling an event loop to stop transferring a request).
147
148.. code-block:: php
149
150    use GuzzleHttp\Ring\Future\FutureValue;
151    use React\Promise\Deferred;
152
153    $deferred = new Deferred();
154    $promise = $deferred->promise();
155
156    $f = new FutureValue(
157        $promise,
158        function () use ($deferred) {
159            // This function is responsible for blocking and resolving the
160            // promise. Here we pass in a reference to the deferred so that
161            // it can be resolved or rejected.
162            $deferred->resolve('foo');
163        }
164    );
165