Deferred.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. declare(strict_types=1);
  3. namespace Http\Client\Common;
  4. use Http\Promise\Promise;
  5. use Psr\Http\Client\ClientExceptionInterface;
  6. use Psr\Http\Message\ResponseInterface;
  7. /**
  8. * A deferred allow to return a promise which has not been resolved yet.
  9. */
  10. final class Deferred implements Promise
  11. {
  12. /**
  13. * @var ResponseInterface|null
  14. */
  15. private $value;
  16. /**
  17. * @var ClientExceptionInterface|null
  18. */
  19. private $failure;
  20. /**
  21. * @var string
  22. */
  23. private $state;
  24. /**
  25. * @var callable
  26. */
  27. private $waitCallback;
  28. /**
  29. * @var callable[]
  30. */
  31. private $onFulfilledCallbacks;
  32. /**
  33. * @var callable[]
  34. */
  35. private $onRejectedCallbacks;
  36. public function __construct(callable $waitCallback)
  37. {
  38. $this->waitCallback = $waitCallback;
  39. $this->state = Promise::PENDING;
  40. $this->onFulfilledCallbacks = [];
  41. $this->onRejectedCallbacks = [];
  42. }
  43. /**
  44. * {@inheritdoc}
  45. */
  46. public function then(callable $onFulfilled = null, callable $onRejected = null): Promise
  47. {
  48. $deferred = new self($this->waitCallback);
  49. $this->onFulfilledCallbacks[] = function (ResponseInterface $response) use ($onFulfilled, $deferred) {
  50. try {
  51. if (null !== $onFulfilled) {
  52. $response = $onFulfilled($response);
  53. }
  54. $deferred->resolve($response);
  55. } catch (ClientExceptionInterface $exception) {
  56. $deferred->reject($exception);
  57. }
  58. };
  59. $this->onRejectedCallbacks[] = function (ClientExceptionInterface $exception) use ($onRejected, $deferred) {
  60. try {
  61. if (null !== $onRejected) {
  62. $response = $onRejected($exception);
  63. $deferred->resolve($response);
  64. return;
  65. }
  66. $deferred->reject($exception);
  67. } catch (ClientExceptionInterface $newException) {
  68. $deferred->reject($newException);
  69. }
  70. };
  71. return $deferred;
  72. }
  73. /**
  74. * {@inheritdoc}
  75. */
  76. public function getState(): string
  77. {
  78. return $this->state;
  79. }
  80. /**
  81. * Resolve this deferred with a Response.
  82. */
  83. public function resolve(ResponseInterface $response): void
  84. {
  85. if (Promise::PENDING !== $this->state) {
  86. return;
  87. }
  88. $this->value = $response;
  89. $this->state = Promise::FULFILLED;
  90. foreach ($this->onFulfilledCallbacks as $onFulfilledCallback) {
  91. $onFulfilledCallback($response);
  92. }
  93. }
  94. /**
  95. * Reject this deferred with an Exception.
  96. */
  97. public function reject(ClientExceptionInterface $exception): void
  98. {
  99. if (Promise::PENDING !== $this->state) {
  100. return;
  101. }
  102. $this->failure = $exception;
  103. $this->state = Promise::REJECTED;
  104. foreach ($this->onRejectedCallbacks as $onRejectedCallback) {
  105. $onRejectedCallback($exception);
  106. }
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function wait($unwrap = true)
  112. {
  113. if (Promise::PENDING === $this->state) {
  114. $callback = $this->waitCallback;
  115. $callback();
  116. }
  117. if (!$unwrap) {
  118. return null;
  119. }
  120. if (Promise::FULFILLED === $this->state) {
  121. return $this->value;
  122. }
  123. /** @var ClientExceptionInterface */
  124. throw $this->failure;
  125. }
  126. }