Skip to content

Commit 4c6a2ea

Browse files
authored
Merge pull request #60 from clue-labs/loop
Simplify usage by supporting new default loop
2 parents 5906e8d + 514ec9c commit 4c6a2ea

File tree

10 files changed

+111
-61
lines changed

10 files changed

+111
-61
lines changed

README.md

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,17 @@ non-blocking HTTP requests and block until the first (faster) one resolves.
5353
```php
5454
function blockingExample()
5555
{
56-
// use a unique event loop instance for all parallel operations
57-
$loop = React\EventLoop\Factory::create();
58-
5956
// this example uses an HTTP client
6057
// this could be pretty much everything that binds to an event loop
61-
$browser = new React\Http\Browser($loop);
62-
58+
$browser = new React\Http\Browser();
59+
6360
// set up two parallel requests
6461
$request1 = $browser->get('http://www.google.com/');
6562
$request2 = $browser->get('http://www.google.co.uk/');
66-
63+
6764
// keep the loop running (i.e. block) until the first response arrives
68-
$fasterResponse = Clue\React\Block\awaitAny(array($request1, $request2), $loop);
69-
65+
$fasterResponse = Clue\React\Block\awaitAny(array($request1, $request2));
66+
7067
return $fasterResponse->getBody();
7168
}
7269
```
@@ -98,19 +95,9 @@ use Clue\React\Block;
9895
Block\await(…);
9996
```
10097

101-
### EventLoop
102-
103-
Each function is responsible for orchestrating the
104-
[`EventLoop`](https://github.com/reactphp/event-loop#usage)
105-
in order to make it run (block) until your conditions are fulfilled.
106-
107-
```php
108-
$loop = React\EventLoop\Factory::create();
109-
```
110-
11198
### sleep()
11299

113-
The `sleep($seconds, LoopInterface $loop): void` function can be used to
100+
The `sleep(float $seconds, ?LoopInterface $loop = null): void` function can be used to
114101
wait/sleep for `$time` seconds.
115102

116103
```php
@@ -127,13 +114,19 @@ it keeps running until this timer triggers. This implies that if you pass a
127114
really small (or negative) value, it will still start a timer and will thus
128115
trigger at the earliest possible time in the future.
129116

117+
This function takes an optional `LoopInterface|null $loop` parameter that can be used to
118+
pass the event loop instance to use. You can use a `null` value here in order to
119+
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
120+
SHOULD NOT be given unless you're sure you want to explicitly use a given event
121+
loop instance.
122+
130123
### await()
131124

132-
The `await(PromiseInterface $promise, LoopInterface $loop, ?float $timeout = null): mixed` function can be used to
125+
The `await(PromiseInterface $promise, ?LoopInterface $loop = null, ?float $timeout = null): mixed` function can be used to
133126
block waiting for the given `$promise` to be fulfilled.
134127

135128
```php
136-
$result = Clue\React\Block\await($promise, $loop);
129+
$result = Clue\React\Block\await($promise);
137130
```
138131

139132
This function will only return after the given `$promise` has settled, i.e.
@@ -149,7 +142,7 @@ will throw an `UnexpectedValueException` instead.
149142

150143
```php
151144
try {
152-
$result = Clue\React\Block\await($promise, $loop);
145+
$result = Clue\React\Block\await($promise);
153146
// promise successfully fulfilled with $result
154147
echo 'Result: ' . $result;
155148
} catch (Exception $exception) {
@@ -160,6 +153,12 @@ try {
160153

161154
See also the [examples](examples/).
162155

156+
This function takes an optional `LoopInterface|null $loop` parameter that can be used to
157+
pass the event loop instance to use. You can use a `null` value here in order to
158+
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
159+
SHOULD NOT be given unless you're sure you want to explicitly use a given event
160+
loop instance.
161+
163162
If no `$timeout` argument is given and the promise stays pending, then this
164163
will potentially wait/block forever until the promise is settled. To avoid
165164
this, API authors creating promises are expected to provide means to
@@ -173,7 +172,7 @@ start a timer and will thus trigger at the earliest possible time in the future.
173172

174173
### awaitAny()
175174

176-
The `awaitAny(PromiseInterface[] $promises, LoopInterface $loop, ?float $timeout = null): mixed` function can be used to
175+
The `awaitAny(PromiseInterface[] $promises, ?LoopInterface $loop = null, ?float $timeout = null): mixed` function can be used to
177176
wait for ANY of the given promises to be fulfilled.
178177

179178
```php
@@ -182,7 +181,7 @@ $promises = array(
182181
$promise2
183182
);
184183

185-
$firstResult = Clue\React\Block\awaitAny($promises, $loop);
184+
$firstResult = Clue\React\Block\awaitAny($promises);
186185

187186
echo 'First result: ' . $firstResult;
188187
```
@@ -199,6 +198,12 @@ promise resolved to and will try to `cancel()` all remaining promises.
199198
Once ALL promises reject, this function will fail and throw an `UnderflowException`.
200199
Likewise, this will throw if an empty array of `$promises` is passed.
201200

201+
This function takes an optional `LoopInterface|null $loop` parameter that can be used to
202+
pass the event loop instance to use. You can use a `null` value here in order to
203+
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
204+
SHOULD NOT be given unless you're sure you want to explicitly use a given event
205+
loop instance.
206+
202207
If no `$timeout` argument is given and ALL promises stay pending, then this
203208
will potentially wait/block forever until the promise is fulfilled. To avoid
204209
this, API authors creating promises are expected to provide means to
@@ -213,7 +218,7 @@ possible time in the future.
213218

214219
### awaitAll()
215220

216-
The `awaitAll(PromiseInterface[] $promises, LoopInterface $loop, ?float $timeout = null): mixed[]` function can be used to
221+
The `awaitAll(PromiseInterface[] $promises, ?LoopInterface $loop = null, ?float $timeout = null): mixed[]` function can be used to
217222
wait for ALL of the given promises to be fulfilled.
218223

219224
```php
@@ -222,7 +227,7 @@ $promises = array(
222227
$promise2
223228
);
224229

225-
$allResults = Clue\React\Block\awaitAll($promises, $loop);
230+
$allResults = Clue\React\Block\awaitAll($promises);
226231

227232
echo 'First promise resolved with: ' . $allResults[0];
228233
```
@@ -242,6 +247,12 @@ Once ANY promise rejects, this will try to `cancel()` all remaining promises
242247
and throw an `Exception`. If the promise did not reject with an `Exception`,
243248
then this function will throw an `UnexpectedValueException` instead.
244249

250+
This function takes an optional `LoopInterface|null $loop` parameter that can be used to
251+
pass the event loop instance to use. You can use a `null` value here in order to
252+
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
253+
SHOULD NOT be given unless you're sure you want to explicitly use a given event
254+
loop instance.
255+
245256
If no `$timeout` argument is given and ANY promises stay pending, then this
246257
will potentially wait/block forever until the promise is fulfilled. To avoid
247258
this, API authors creating promises are expected to provide means to

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
},
1919
"require": {
2020
"php": ">=5.3",
21-
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
21+
"react/event-loop": "^1.2",
2222
"react/promise": "^2.7 || ^1.2.1",
2323
"react/promise-timer": "^1.5"
2424
},
2525
"require-dev": {
2626
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
27-
"react/http": "^1.0"
27+
"react/http": "^1.4"
2828
}
2929
}

examples/01-await.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@
99
*/
1010
function requestHttp($url)
1111
{
12-
// use a unique event loop instance for this operation
13-
$loop = React\EventLoop\Factory::create();
14-
1512
// This example uses an HTTP client
16-
$browser = new React\Http\Browser($loop);
13+
$browser = new React\Http\Browser();
1714

1815
// set up one request
1916
$promise = $browser->get($url);
2017

2118
try {
2219
// keep the loop running (i.e. block) until the response arrives
23-
$result = Clue\React\Block\await($promise, $loop);
20+
$result = Clue\React\Block\await($promise);
2421

2522
// promise successfully fulfilled with $result
2623
return $result;

examples/02-await-any.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010
*/
1111
function requestHttpFastestOfMultiple($url1, $url2)
1212
{
13-
// use a unique event loop instance for all parallel operations
14-
$loop = React\EventLoop\Factory::create();
15-
1613
// This example uses an HTTP client
17-
$browser = new React\Http\Browser($loop);
14+
$browser = new React\Http\Browser();
1815

1916
// set up two parallel requests
2017
$promises = array(
@@ -24,7 +21,7 @@ function requestHttpFastestOfMultiple($url1, $url2)
2421

2522
try {
2623
// keep the loop running (i.e. block) until the first response arrives
27-
$fasterResponse = Clue\React\Block\awaitAny($promises, $loop);
24+
$fasterResponse = Clue\React\Block\awaitAny($promises);
2825

2926
// promise successfully fulfilled with $fasterResponse
3027
return $fasterResponse;

examples/03-await-all.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010
*/
1111
function requestHttpMultiple($url1, $url2)
1212
{
13-
// use a unique event loop instance for all parallel operations
14-
$loop = React\EventLoop\Factory::create();
15-
1613
// This example uses an HTTP client
17-
$browser = new React\Http\Browser($loop);
14+
$browser = new React\Http\Browser();
1815

1916
// set up two parallel requests
2017
$promises = array(
@@ -24,7 +21,7 @@ function requestHttpMultiple($url1, $url2)
2421

2522
try {
2623
// keep the loop running (i.e. block) until all responses arrive
27-
$allResults = Clue\React\Block\awaitAll($promises, $loop);
24+
$allResults = Clue\React\Block\awaitAll($promises);
2825

2926
// promise successfully fulfilled with $allResults
3027
return $allResults;

src/functions.php

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22

33
namespace Clue\React\Block;
44

5+
use React\EventLoop\Loop;
56
use React\EventLoop\LoopInterface;
6-
use React\Promise\PromiseInterface;
7-
use React\Promise\CancellablePromiseInterface;
8-
use UnderflowException;
9-
use Exception;
107
use React\Promise;
8+
use React\Promise\CancellablePromiseInterface;
9+
use React\Promise\PromiseInterface;
1110
use React\Promise\Timer;
1211
use React\Promise\Timer\TimeoutException;
12+
use Exception;
13+
use UnderflowException;
1314

1415
/**
1516
* Wait/sleep for `$time` seconds.
@@ -28,11 +29,17 @@
2829
* really small (or negative) value, it will still start a timer and will thus
2930
* trigger at the earliest possible time in the future.
3031
*
32+
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
33+
* pass the event loop instance to use. You can use a `null` value here in order to
34+
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
35+
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
36+
* loop instance.
37+
*
3138
* @param float $time
32-
* @param LoopInterface $loop
39+
* @param ?LoopInterface $loop
3340
* @return void
3441
*/
35-
function sleep($time, LoopInterface $loop)
42+
function sleep($time, LoopInterface $loop = null)
3643
{
3744
await(Timer\resolve($time, $loop), $loop);
3845
}
@@ -68,6 +75,12 @@ function sleep($time, LoopInterface $loop)
6875
*
6976
* See also the [examples](../examples/).
7077
*
78+
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
79+
* pass the event loop instance to use. You can use a `null` value here in order to
80+
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
81+
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
82+
* loop instance.
83+
*
7184
* If no `$timeout` argument is given and the promise stays pending, then this
7285
* will potentially wait/block forever until the promise is settled. To avoid
7386
* this, API authors creating promises are expected to provide means to
@@ -80,18 +93,19 @@ function sleep($time, LoopInterface $loop)
8093
* start a timer and will thus trigger at the earliest possible time in the future.
8194
*
8295
* @param PromiseInterface $promise
83-
* @param LoopInterface $loop
84-
* @param null|float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
96+
* @param ?LoopInterface $loop
97+
* @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
8598
* @return mixed returns whatever the promise resolves to
8699
* @throws Exception when the promise is rejected
87100
* @throws TimeoutException if the $timeout is given and triggers
88101
*/
89-
function await(PromiseInterface $promise, LoopInterface $loop, $timeout = null)
102+
function await(PromiseInterface $promise, LoopInterface $loop = null, $timeout = null)
90103
{
91104
$wait = true;
92105
$resolved = null;
93106
$exception = null;
94107
$rejected = false;
108+
$loop = $loop ?: Loop::get();
95109

96110
if ($timeout !== null) {
97111
$promise = Timer\timeout($promise, $timeout, $loop);
@@ -164,6 +178,12 @@ function ($error) use (&$exception, &$rejected, &$wait, $loop) {
164178
* Once ALL promises reject, this function will fail and throw an `UnderflowException`.
165179
* Likewise, this will throw if an empty array of `$promises` is passed.
166180
*
181+
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
182+
* pass the event loop instance to use. You can use a `null` value here in order to
183+
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
184+
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
185+
* loop instance.
186+
*
167187
* If no `$timeout` argument is given and ALL promises stay pending, then this
168188
* will potentially wait/block forever until the promise is fulfilled. To avoid
169189
* this, API authors creating promises are expected to provide means to
@@ -176,14 +196,14 @@ function ($error) use (&$exception, &$rejected, &$wait, $loop) {
176196
* value, it will still start a timer and will thus trigger at the earliest
177197
* possible time in the future.
178198
*
179-
* @param array $promises
180-
* @param LoopInterface $loop
181-
* @param null|float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
199+
* @param array $promises
200+
* @param ?LoopInterface $loop
201+
* @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
182202
* @return mixed returns whatever the first promise resolves to
183203
* @throws Exception if ALL promises are rejected
184204
* @throws TimeoutException if the $timeout is given and triggers
185205
*/
186-
function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
206+
function awaitAny(array $promises, LoopInterface $loop = null, $timeout = null)
187207
{
188208
// Explicitly overwrite argument with null value. This ensure that this
189209
// argument does not show up in the stack trace in PHP 7+ only.
@@ -249,6 +269,12 @@ function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
249269
* and throw an `Exception`. If the promise did not reject with an `Exception`,
250270
* then this function will throw an `UnexpectedValueException` instead.
251271
*
272+
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
273+
* pass the event loop instance to use. You can use a `null` value here in order to
274+
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
275+
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
276+
* loop instance.
277+
*
252278
* If no `$timeout` argument is given and ANY promises stay pending, then this
253279
* will potentially wait/block forever until the promise is fulfilled. To avoid
254280
* this, API authors creating promises are expected to provide means to
@@ -261,14 +287,14 @@ function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
261287
* value, it will still start a timer and will thus trigger at the earliest
262288
* possible time in the future.
263289
*
264-
* @param array $promises
265-
* @param LoopInterface $loop
266-
* @param null|float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
290+
* @param array $promises
291+
* @param ?LoopInterface $loop
292+
* @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
267293
* @return array returns an array with whatever each promise resolves to
268294
* @throws Exception when ANY promise is rejected
269295
* @throws TimeoutException if the $timeout is given and triggers
270296
*/
271-
function awaitAll(array $promises, LoopInterface $loop, $timeout = null)
297+
function awaitAll(array $promises, LoopInterface $loop = null, $timeout = null)
272298
{
273299
// Explicitly overwrite argument with null value. This ensure that this
274300
// argument does not show up in the stack trace in PHP 7+ only.

tests/FunctionAwaitAllTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ public function testAwaitAllAllResolved()
2323
$this->assertEquals(array('first' => 1, 'second' => 2), Block\awaitAll($all, $this->loop));
2424
}
2525

26+
public function testAwaitAllReturnsArrayWithFulfilledValueFromSinglePromiseWithoutGivingLoop()
27+
{
28+
$promise = Promise\resolve(42);
29+
30+
$this->assertEquals(array(42), Block\awaitAll(array($promise)));
31+
}
32+
2633
public function testAwaitAllRejected()
2734
{
2835
$all = array(

0 commit comments

Comments
 (0)