GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 5cefd1...492078 )
by Anton
04:08
created

timeout()   B

Complexity

Conditions 11
Paths 4

Size

Total Lines 51
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 27
c 0
b 0
f 0
nc 4
nop 3
dl 0
loc 51
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace React\Promise\Timer;
4
5
use React\EventLoop\Loop;
6
use React\EventLoop\LoopInterface;
7
use React\Promise\CancellablePromiseInterface;
8
use React\Promise\Promise;
9
use React\Promise\PromiseInterface;
10
11
/**
12
 * Cancel operations that take *too long*.
13
 *
14
 * You need to pass in an input `$promise` that represents a pending operation
15
 * and timeout parameters. It returns a new promise with the following
16
 * resolution behavior:
17
 *
18
 * - If the input `$promise` resolves before `$time` seconds, resolve the
19
 *   resulting promise with its fulfillment value.
20
 *
21
 * - If the input `$promise` rejects before `$time` seconds, reject the
22
 *   resulting promise with its rejection value.
23
 *
24
 * - If the input `$promise` does not settle before `$time` seconds, *cancel*
25
 *   the operation and reject the resulting promise with a [`TimeoutException`](#timeoutexception).
26
 *
27
 * Internally, the given `$time` value will be used to start a timer that will
28
 * *cancel* the pending operation once it triggers. This implies that if you
29
 * pass a really small (or negative) value, it will still start a timer and will
30
 * thus trigger at the earliest possible time in the future.
31
 *
32
 * If the input `$promise` is already settled, then the resulting promise will
33
 * resolve or reject immediately without starting a timer at all.
34
 *
35
 * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
36
 * pass the event loop instance to use. You can use a `null` value here in order to
37
 * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
38
 * SHOULD NOT be given unless you're sure you want to explicitly use a given event
39
 * loop instance.
40
 *
41
 * A common use case for handling only resolved values looks like this:
42
 *
43
 * ```php
44
 * $promise = accessSomeRemoteResource();
45
 * React\Promise\Timer\timeout($promise, 10.0)->then(function ($value) {
46
 *     // the operation finished within 10.0 seconds
47
 * });
48
 * ```
49
 *
50
 * A more complete example could look like this:
51
 *
52
 * ```php
53
 * $promise = accessSomeRemoteResource();
54
 * React\Promise\Timer\timeout($promise, 10.0)->then(
55
 *     function ($value) {
56
 *         // the operation finished within 10.0 seconds
57
 *     },
58
 *     function ($error) {
59
 *         if ($error instanceof React\Promise\Timer\TimeoutException) {
60
 *             // the operation has failed due to a timeout
61
 *         } else {
62
 *             // the input operation has failed due to some other error
63
 *         }
64
 *     }
65
 * );
66
 * ```
67
 *
68
 * Or if you're using [react/promise v2.2.0](https://github.com/reactphp/promise) or up:
69
 *
70
 * ```php
71
 * React\Promise\Timer\timeout($promise, 10.0)
72
 *     ->then(function ($value) {
73
 *         // the operation finished within 10.0 seconds
74
 *     })
75
 *     ->otherwise(function (React\Promise\Timer\TimeoutException $error) {
76
 *         // the operation has failed due to a timeout
77
 *     })
78
 *     ->otherwise(function ($error) {
79
 *         // the input operation has failed due to some other error
80
 *     })
81
 * ;
82
 * ```
83
 *
84
 * As discussed above, the [`timeout()`](#timeout) function will take care of
85
 * the underlying operation if it takes *too long*. In this case, you can be
86
 * sure the resulting promise will always be rejected with a
87
 * [`TimeoutException`](#timeoutexception). On top of this, the function will
88
 * try to *cancel* the underlying operation. Responsibility for this
89
 * cancellation logic is left up to the underlying operation.
90
 *
91
 * - A common use case involves cleaning up any resources like open network
92
 *   sockets or file handles or terminating external processes or timers.
93
 *
94
 * - If the given input `$promise` does not support cancellation, then this is a
95
 *   NO-OP. This means that while the resulting promise will still be rejected,
96
 *   the underlying input `$promise` may still be pending and can hence continue
97
 *   consuming resources
98
 *
99
 * On top of this, the returned promise is implemented in such a way that it can
100
 * be cancelled when it is still pending. Cancelling a pending promise will
101
 * cancel the underlying operation. As discussed above, responsibility for this
102
 * cancellation logic is left up to the underlying operation.
103
 *
104
 * ```php
105
 * $promise = accessSomeRemoteResource();
106
 * $timeout = React\Promise\Timer\timeout($promise, 10.0);
107
 *
108
 * $timeout->cancel();
109
 * ```
110
 *
111
 * For more details on the promise cancellation, please refer to the
112
 * [Promise documentation](https://github.com/reactphp/promise#cancellablepromiseinterface).
113
 *
114
 * If you want to wait for multiple promises to resolve, you can use the normal
115
 * promise primitives like this:
116
 *
117
 * ```php
118
 * $promises = array(
119
 *     accessSomeRemoteResource(),
120
 *     accessSomeRemoteResource(),
121
 *     accessSomeRemoteResource()
122
 * );
123
 *
124
 * $promise = React\Promise\all($promises);
125
 *
126
 * React\Promise\Timer\timeout($promise, 10)->then(function ($values) {
127
 *     // *all* promises resolved
128
 * });
129
 * ```
130
 *
131
 * The applies to all promise collection primitives alike, i.e. `all()`,
132
 * `race()`, `any()`, `some()` etc.
133
 *
134
 * For more details on the promise primitives, please refer to the
135
 * [Promise documentation](https://github.com/reactphp/promise#functions).
136
 *
137
 * @param PromiseInterface<mixed, \Exception|mixed> $promise
138
 * @param float $time
139
 * @param ?LoopInterface $loop
140
 * @return PromiseInterface<mixed, TimeoutException|\Exception|mixed>
141
 */
142
function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null)
143
{
144
    // cancelling this promise will only try to cancel the input promise,
145
    // thus leaving responsibility to the input promise.
146
    $canceller = null;
147
    if ($promise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {
148
        // pass promise by reference to clean reference after cancellation handler
149
        // has been invoked once in order to avoid garbage references in call stack.
150
        $canceller = function () use (&$promise) {
151
            $promise->cancel();
152
            $promise = null;
153
        };
154
    }
155
156
    if ($loop === null) {
157
        $loop = Loop::get();
158
    }
159
160
    return new Promise(function ($resolve, $reject) use ($loop, $time, $promise) {
161
        $timer = null;
162
        $promise = $promise->then(function ($v) use (&$timer, $loop, $resolve) {
163
            if ($timer) {
164
                $loop->cancelTimer($timer);
165
            }
166
            $timer = false;
167
            $resolve($v);
168
        }, function ($v) use (&$timer, $loop, $reject) {
169
            if ($timer) {
170
                $loop->cancelTimer($timer);
171
            }
172
            $timer = false;
173
            $reject($v);
174
        });
175
176
        // promise already resolved => no need to start timer
177
        if ($timer === false) {
178
            return;
179
        }
180
181
        // start timeout timer which will cancel the input promise
182
        $timer = $loop->addTimer($time, function () use ($time, &$promise, $reject) {
0 ignored issues
show
Unused Code introduced by
The assignment to $timer is dead and can be removed.
Loading history...
183
            $reject(new TimeoutException($time, 'Timed out after ' . $time . ' seconds'));
184
185
            // try to invoke cancellation handler of input promise and then clean
186
            // reference in order to avoid garbage references in call stack.
187
            if ($promise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {
188
                $promise->cancel();
189
            }
190
            $promise = null;
191
        });
192
    }, $canceller);
193
}
194
195
/**
196
 * Create a new promise that resolves in `$time` seconds.
197
 *
198
 * ```php
199
 * React\Promise\Timer\sleep(1.5)->then(function () {
200
 *     echo 'Thanks for waiting!' . PHP_EOL;
201
 * });
202
 * ```
203
 *
204
 * Internally, the given `$time` value will be used to start a timer that will
205
 * resolve the promise once it triggers. This implies that if you pass a really
206
 * small (or negative) value, it will still start a timer and will thus trigger
207
 * at the earliest possible time in the future.
208
 *
209
 * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
210
 * pass the event loop instance to use. You can use a `null` value here in order to
211
 * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
212
 * SHOULD NOT be given unless you're sure you want to explicitly use a given event
213
 * loop instance.
214
 *
215
 * The returned promise is implemented in such a way that it can be cancelled
216
 * when it is still pending. Cancelling a pending promise will reject its value
217
 * with a `RuntimeException` and clean up any pending timers.
218
 *
219
 * ```php
220
 * $timer = React\Promise\Timer\sleep(2.0);
221
 *
222
 * $timer->cancel();
223
 * ```
224
 *
225
 * @param float $time
226
 * @param ?LoopInterface $loop
227
 * @return PromiseInterface<void, \RuntimeException>
228
 */
229
function sleep($time, LoopInterface $loop = null)
230
{
231
    if ($loop === null) {
232
        $loop = Loop::get();
233
    }
234
235
    $timer = null;
236
    return new Promise(function ($resolve) use ($loop, $time, &$timer) {
237
        // resolve the promise when the timer fires in $time seconds
238
        $timer = $loop->addTimer($time, function () use ($resolve) {
239
            $resolve();
240
        });
241
    }, function () use (&$timer, $loop) {
242
        // cancelling this promise will cancel the timer, clean the reference
243
        // in order to avoid garbage references in call stack and then reject.
244
        $loop->cancelTimer($timer);
245
        $timer = null;
246
247
        throw new \RuntimeException('Timer cancelled');
248
    });
249
}
250
251
/**
252
 * [Deprecated] Create a new promise that resolves in `$time` seconds with the `$time` as the fulfillment value.
253
 *
254
 * ```php
255
 * React\Promise\Timer\resolve(1.5)->then(function ($time) {
256
 *     echo 'Thanks for waiting ' . $time . ' seconds' . PHP_EOL;
257
 * });
258
 * ```
259
 *
260
 * Internally, the given `$time` value will be used to start a timer that will
261
 * resolve the promise once it triggers. This implies that if you pass a really
262
 * small (or negative) value, it will still start a timer and will thus trigger
263
 * at the earliest possible time in the future.
264
 *
265
 * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
266
 * pass the event loop instance to use. You can use a `null` value here in order to
267
 * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
268
 * SHOULD NOT be given unless you're sure you want to explicitly use a given event
269
 * loop instance.
270
 *
271
 * The returned promise is implemented in such a way that it can be cancelled
272
 * when it is still pending. Cancelling a pending promise will reject its value
273
 * with a `RuntimeException` and clean up any pending timers.
274
 *
275
 * ```php
276
 * $timer = React\Promise\Timer\resolve(2.0);
277
 *
278
 * $timer->cancel();
279
 * ```
280
 *
281
 * @param float $time
282
 * @param ?LoopInterface $loop
283
 * @return PromiseInterface<float, \RuntimeException>
284
 * @deprecated 1.8.0 See `sleep()` instead
285
 * @see sleep()
286
 */
287
function resolve($time, LoopInterface $loop = null)
288
{
289
    return sleep($time, $loop)->then(function() use ($time) {
290
        return $time;
291
    });
292
}
293
294
/**
295
 * [Deprecated] Create a new promise which rejects in `$time` seconds with a `TimeoutException`.
296
 *
297
 * ```php
298
 * React\Promise\Timer\reject(2.0)->then(null, function (React\Promise\Timer\TimeoutException $e) {
299
 *     echo 'Rejected after ' . $e->getTimeout() . ' seconds ' . PHP_EOL;
300
 * });
301
 * ```
302
 *
303
 * Internally, the given `$time` value will be used to start a timer that will
304
 * reject the promise once it triggers. This implies that if you pass a really
305
 * small (or negative) value, it will still start a timer and will thus trigger
306
 * at the earliest possible time in the future.
307
 *
308
 * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
309
 * pass the event loop instance to use. You can use a `null` value here in order to
310
 * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
311
 * SHOULD NOT be given unless you're sure you want to explicitly use a given event
312
 * loop instance.
313
 *
314
 * The returned promise is implemented in such a way that it can be cancelled
315
 * when it is still pending. Cancelling a pending promise will reject its value
316
 * with a `RuntimeException` and clean up any pending timers.
317
 *
318
 * ```php
319
 * $timer = React\Promise\Timer\reject(2.0);
320
 *
321
 * $timer->cancel();
322
 * ```
323
 *
324
 * @param float         $time
325
 * @param LoopInterface $loop
326
 * @return PromiseInterface<void, TimeoutException|\RuntimeException>
327
 * @deprecated 1.8.0 See `sleep()` instead
328
 * @see sleep()
329
 */
330
function reject($time, LoopInterface $loop = null)
331
{
332
    return sleep($time, $loop)->then(function () use ($time) {
333
        throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');
334
    });
335
}
336