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