Skip to content

Commit 9b92ce5

Browse files
committed
Improve type definitions and update to PHPStan level max
1 parent 303107b commit 9b92ce5

11 files changed

+121
-101
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ To run the test suite, go to the project root and run:
426426
vendor/bin/phpunit
427427
```
428428

429-
On top of this, we use PHPStan on level 3 to ensure type safety across the project:
429+
On top of this, we use PHPStan on max level to ensure type safety across the project:
430430

431431
```bash
432432
vendor/bin/phpstan

phpstan.neon.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
parameters:
2-
level: 3
2+
level: max
33

44
paths:
55
- src/

src/functions.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ function await(PromiseInterface $promise)
5656
$resolved = null;
5757
$exception = null;
5858
$rejected = false;
59+
60+
/** @var bool $loopStarted */
5961
$loopStarted = false;
6062

6163
$promise->then(
@@ -294,7 +296,7 @@ function delay(float $seconds): void
294296
* });
295297
* ```
296298
*
297-
* @param callable(mixed ...$args):\Generator<mixed,PromiseInterface,mixed,mixed> $function
299+
* @param callable(mixed ...$args):(\Generator<mixed,PromiseInterface,mixed,mixed>|mixed) $function
298300
* @param mixed ...$args Optional list of additional arguments that will be passed to the given `$function` as is
299301
* @return PromiseInterface<mixed>
300302
* @since 3.0.0
@@ -313,6 +315,7 @@ function coroutine(callable $function, ...$args): PromiseInterface
313315

314316
$promise = null;
315317
$deferred = new Deferred(function () use (&$promise) {
318+
/** @var ?PromiseInterface $promise */
316319
if ($promise instanceof PromiseInterface && \method_exists($promise, 'cancel')) {
317320
$promise->cancel();
318321
}
@@ -333,6 +336,7 @@ function coroutine(callable $function, ...$args): PromiseInterface
333336
return;
334337
}
335338

339+
/** @var mixed $promise */
336340
$promise = $generator->current();
337341
if (!$promise instanceof PromiseInterface) {
338342
$next = null;
@@ -342,6 +346,7 @@ function coroutine(callable $function, ...$args): PromiseInterface
342346
return;
343347
}
344348

349+
assert($next instanceof \Closure);
345350
$promise->then(function ($value) use ($generator, $next) {
346351
$generator->send($value);
347352
$next();
@@ -364,6 +369,7 @@ function coroutine(callable $function, ...$args): PromiseInterface
364369
*/
365370
function parallel(iterable $tasks): PromiseInterface
366371
{
372+
/** @var array<int,PromiseInterface> $pending */
367373
$pending = [];
368374
$deferred = new Deferred(function () use (&$pending) {
369375
foreach ($pending as $promise) {
@@ -425,6 +431,7 @@ function series(iterable $tasks): PromiseInterface
425431
{
426432
$pending = null;
427433
$deferred = new Deferred(function () use (&$pending) {
434+
/** @var ?PromiseInterface $pending */
428435
if ($pending instanceof PromiseInterface && \method_exists($pending, 'cancel')) {
429436
$pending->cancel();
430437
}
@@ -439,7 +446,7 @@ function series(iterable $tasks): PromiseInterface
439446

440447
$taskCallback = function ($result) use (&$results, &$next) {
441448
$results[] = $result;
442-
assert($next instanceof \Closure);
449+
/** @var \Closure $next */
443450
$next();
444451
};
445452

@@ -453,9 +460,11 @@ function series(iterable $tasks): PromiseInterface
453460
$task = $tasks->current();
454461
$tasks->next();
455462
} else {
463+
assert(\is_array($tasks));
456464
$task = \array_shift($tasks);
457465
}
458466

467+
assert(\is_callable($task));
459468
$promise = \call_user_func($task);
460469
assert($promise instanceof PromiseInterface);
461470
$pending = $promise;
@@ -469,13 +478,14 @@ function series(iterable $tasks): PromiseInterface
469478
}
470479

471480
/**
472-
* @param iterable<callable(mixed=):PromiseInterface<mixed>> $tasks
481+
* @param iterable<(callable():PromiseInterface<mixed>)|(callable(mixed):PromiseInterface<mixed>)> $tasks
473482
* @return PromiseInterface<mixed>
474483
*/
475484
function waterfall(iterable $tasks): PromiseInterface
476485
{
477486
$pending = null;
478487
$deferred = new Deferred(function () use (&$pending) {
488+
/** @var ?PromiseInterface $pending */
479489
if ($pending instanceof PromiseInterface && \method_exists($pending, 'cancel')) {
480490
$pending->cancel();
481491
}
@@ -498,9 +508,11 @@ function waterfall(iterable $tasks): PromiseInterface
498508
$task = $tasks->current();
499509
$tasks->next();
500510
} else {
511+
assert(\is_array($tasks));
501512
$task = \array_shift($tasks);
502513
}
503514

515+
assert(\is_callable($task));
504516
$promise = \call_user_func_array($task, func_get_args());
505517
assert($promise instanceof PromiseInterface);
506518
$pending = $promise;

tests/AwaitTest.php

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class AwaitTest extends TestCase
1010
{
11-
public function testAwaitThrowsExceptionWhenPromiseIsRejectedWithException()
11+
public function testAwaitThrowsExceptionWhenPromiseIsRejectedWithException(): void
1212
{
1313
$promise = new Promise(function () {
1414
throw new \Exception('test');
@@ -19,7 +19,7 @@ public function testAwaitThrowsExceptionWhenPromiseIsRejectedWithException()
1919
React\Async\await($promise);
2020
}
2121

22-
public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWithFalse()
22+
public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWithFalse(): void
2323
{
2424
if (!interface_exists('React\Promise\CancellablePromiseInterface')) {
2525
$this->markTestSkipped('Promises must be rejected with a \Throwable instance since Promise v3');
@@ -34,7 +34,7 @@ public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWith
3434
React\Async\await($promise);
3535
}
3636

37-
public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWithNull()
37+
public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWithNull(): void
3838
{
3939
if (!interface_exists('React\Promise\CancellablePromiseInterface')) {
4040
$this->markTestSkipped('Promises must be rejected with a \Throwable instance since Promise v3');
@@ -49,7 +49,7 @@ public function testAwaitThrowsUnexpectedValueExceptionWhenPromiseIsRejectedWith
4949
React\Async\await($promise);
5050
}
5151

52-
public function testAwaitThrowsErrorWhenPromiseIsRejectedWithError()
52+
public function testAwaitThrowsErrorWhenPromiseIsRejectedWithError(): void
5353
{
5454
$promise = new Promise(function ($_, $reject) {
5555
throw new \Error('Test', 42);
@@ -61,7 +61,7 @@ public function testAwaitThrowsErrorWhenPromiseIsRejectedWithError()
6161
React\Async\await($promise);
6262
}
6363

64-
public function testAwaitReturnsValueWhenPromiseIsFullfilled()
64+
public function testAwaitReturnsValueWhenPromiseIsFullfilled(): void
6565
{
6666
$promise = new Promise(function ($resolve) {
6767
$resolve(42);
@@ -70,7 +70,7 @@ public function testAwaitReturnsValueWhenPromiseIsFullfilled()
7070
$this->assertEquals(42, React\Async\await($promise));
7171
}
7272

73-
public function testAwaitReturnsValueWhenPromiseIsFulfilledEvenWhenOtherTimerStopsLoop()
73+
public function testAwaitReturnsValueWhenPromiseIsFulfilledEvenWhenOtherTimerStopsLoop(): void
7474
{
7575
$promise = new Promise(function ($resolve) {
7676
Loop::addTimer(0.02, function () use ($resolve) {
@@ -84,7 +84,7 @@ public function testAwaitReturnsValueWhenPromiseIsFulfilledEvenWhenOtherTimerSto
8484
$this->assertEquals(2, React\Async\await($promise));
8585
}
8686

87-
public function testAwaitWithAlreadyFulfilledPromiseWillReturnWithoutRunningLoop()
87+
public function testAwaitWithAlreadyFulfilledPromiseWillReturnWithoutRunningLoop(): void
8888
{
8989
$now = true;
9090

@@ -100,7 +100,7 @@ public function testAwaitWithAlreadyFulfilledPromiseWillReturnWithoutRunningLoop
100100
$this->assertTrue($now);
101101
}
102102

103-
public function testAwaitWithAlreadyFulfilledPromiseWillReturnWithoutStoppingLoop()
103+
public function testAwaitWithAlreadyFulfilledPromiseWillReturnWithoutStoppingLoop(): void
104104
{
105105
$ticks = 0;
106106

@@ -128,7 +128,7 @@ public function testAwaitWithAlreadyFulfilledPromiseWillReturnWithoutStoppingLoo
128128
$this->assertEquals(2, $ticks);
129129
}
130130

131-
public function testAwaitWithPendingPromiseThatWillResolveWillStopLoopBeforeLastTimerFinishes()
131+
public function testAwaitWithPendingPromiseThatWillResolveWillStopLoopBeforeLastTimerFinishes(): void
132132
{
133133
$promise = new Promise(function ($resolve) {
134134
Loop::addTimer(0.02, function () use ($resolve) {
@@ -159,7 +159,7 @@ public function testAwaitWithPendingPromiseThatWillResolveWillStopLoopBeforeLast
159159
$this->assertEquals(1, $ticks);
160160
}
161161

162-
public function testAwaitWithAlreadyRejectedPromiseWillReturnWithoutStoppingLoop()
162+
public function testAwaitWithAlreadyRejectedPromiseWillReturnWithoutStoppingLoop(): void
163163
{
164164
$ticks = 0;
165165

@@ -191,7 +191,7 @@ public function testAwaitWithAlreadyRejectedPromiseWillReturnWithoutStoppingLoop
191191
$this->assertEquals(2, $ticks);
192192
}
193193

194-
public function testAwaitWithPendingPromiseThatWillRejectWillStopLoopBeforeLastTimerFinishes()
194+
public function testAwaitWithPendingPromiseThatWillRejectWillStopLoopBeforeLastTimerFinishes(): void
195195
{
196196
$promise = new Promise(function ($_, $reject) {
197197
Loop::addTimer(0.02, function () use (&$reject) {
@@ -227,7 +227,7 @@ public function testAwaitWithPendingPromiseThatWillRejectWillStopLoopBeforeLastT
227227
$this->assertEquals(1, $ticks);
228228
}
229229

230-
public function testAwaitShouldNotCreateAnyGarbageReferencesForResolvedPromise()
230+
public function testAwaitShouldNotCreateAnyGarbageReferencesForResolvedPromise(): void
231231
{
232232
if (class_exists('React\Promise\When')) {
233233
$this->markTestSkipped('Not supported on legacy Promise v1 API');
@@ -244,7 +244,7 @@ public function testAwaitShouldNotCreateAnyGarbageReferencesForResolvedPromise()
244244
$this->assertEquals(0, gc_collect_cycles());
245245
}
246246

247-
public function testAwaitShouldNotCreateAnyGarbageReferencesForRejectedPromise()
247+
public function testAwaitShouldNotCreateAnyGarbageReferencesForRejectedPromise(): void
248248
{
249249
if (class_exists('React\Promise\When')) {
250250
$this->markTestSkipped('Not supported on legacy Promise v1 API');
@@ -265,7 +265,7 @@ public function testAwaitShouldNotCreateAnyGarbageReferencesForRejectedPromise()
265265
$this->assertEquals(0, gc_collect_cycles());
266266
}
267267

268-
public function testAwaitShouldNotCreateAnyGarbageReferencesForPromiseRejectedWithNullValue()
268+
public function testAwaitShouldNotCreateAnyGarbageReferencesForPromiseRejectedWithNullValue(): void
269269
{
270270
if (!interface_exists('React\Promise\CancellablePromiseInterface')) {
271271
$this->markTestSkipped('Promises must be rejected with a \Throwable instance since Promise v3');

0 commit comments

Comments
 (0)