futures.rst 5.5 KB

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