Skip to content

Commit c4e6145

Browse files
committed
Improve type definitions and update to PHPStan level max
1 parent fd5e886 commit c4e6145

39 files changed

+317
-326
lines changed

README.md

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

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

607607
```bash
608608
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/Deferred.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
44

55
final class Deferred
66
{
7+
/** @var Promise */
78
private $promise;
9+
10+
/** @var callable */
811
private $resolveCallback;
12+
13+
/** @var callable */
914
private $rejectCallback;
1015

1116
public function __construct(callable $canceller = null)
@@ -21,6 +26,9 @@ public function promise(): PromiseInterface
2126
return $this->promise;
2227
}
2328

29+
/**
30+
* @param mixed $value
31+
*/
2432
public function resolve($value): void
2533
{
2634
($this->resolveCallback)($value);

src/Exception/CompositeException.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
*/
1212
class CompositeException extends \Exception
1313
{
14+
/** @var \Throwable[] */
1415
private $throwables;
1516

16-
public function __construct(array $throwables, $message = '', $code = 0, $previous = null)
17+
/** @param \Throwable[] $throwables */
18+
public function __construct(array $throwables, string $message = '', int $code = 0, ?\Throwable $previous = null)
1719
{
1820
parent::__construct($message, $code, $previous);
1921

src/Internal/CancellationQueue.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
*/
88
final class CancellationQueue
99
{
10+
/** @var bool */
1011
private $started = false;
12+
13+
/** @var object[] */
1114
private $queue = [];
1215

1316
public function __invoke(): void
@@ -20,6 +23,9 @@ public function __invoke(): void
2023
$this->drain();
2124
}
2225

26+
/**
27+
* @param mixed $cancellable
28+
*/
2329
public function enqueue($cancellable): void
2430
{
2531
if (!\is_object($cancellable) || !\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) {
@@ -37,6 +43,7 @@ private function drain(): void
3743
{
3844
for ($i = \key($this->queue); isset($this->queue[$i]); $i++) {
3945
$cancellable = $this->queue[$i];
46+
assert(\method_exists($cancellable, 'cancel'));
4047

4148
$exception = null;
4249

src/Internal/FulfilledPromise.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@
1010
*/
1111
final class FulfilledPromise implements PromiseInterface
1212
{
13+
/** @var mixed */
1314
private $value;
1415

16+
/**
17+
* @param mixed $value
18+
* @throws \InvalidArgumentException
19+
*/
1520
public function __construct($value = null)
1621
{
1722
if ($value instanceof PromiseInterface) {

src/Internal/RejectedPromise.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
*/
1212
final class RejectedPromise implements PromiseInterface
1313
{
14+
/** @var \Throwable */
1415
private $reason;
1516

17+
/**
18+
* @param \Throwable $reason
19+
*/
1620
public function __construct(\Throwable $reason)
1721
{
1822
$this->reason = $reason;

src/Promise.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@
66

77
final class Promise implements PromiseInterface
88
{
9+
/** @var ?callable */
910
private $canceller;
11+
12+
/** @var ?PromiseInterface */
1013
private $result;
1114

15+
/** @var callable[] */
1216
private $handlers = [];
1317

18+
/** @var int */
1419
private $requiredCancelRequests = 0;
1520

1621
public function __construct(callable $resolver, callable $canceller = null)
@@ -46,6 +51,7 @@ public function then(callable $onFulfilled = null, callable $onRejected = null):
4651
return new static(
4752
$this->resolver($onFulfilled, $onRejected),
4853
static function () use (&$parent) {
54+
assert($parent instanceof self);
4955
--$parent->requiredCancelRequests;
5056

5157
if ($parent->requiredCancelRequests <= 0) {
@@ -187,7 +193,7 @@ private function settle(PromiseInterface $result): void
187193
}
188194
}
189195

190-
private function unwrap($promise): PromiseInterface
196+
private function unwrap(PromiseInterface $promise): PromiseInterface
191197
{
192198
while ($promise instanceof self && null !== $promise->result) {
193199
$promise = $promise->result;
@@ -213,6 +219,7 @@ private function call(callable $cb): void
213219
} elseif (\is_object($callback) && !$callback instanceof \Closure) {
214220
$ref = new \ReflectionMethod($callback, '__invoke');
215221
} else {
222+
assert($callback instanceof \Closure || \is_string($callback));
216223
$ref = new \ReflectionFunction($callback);
217224
}
218225
$args = $ref->getNumberOfParameters();

src/functions.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function reject(\Throwable $reason): PromiseInterface
6868
* will be an array containing the resolution values of each of the items in
6969
* `$promisesOrValues`.
7070
*
71-
* @param iterable $promisesOrValues
71+
* @param iterable<mixed> $promisesOrValues
7272
* @return PromiseInterface
7373
*/
7474
function all(iterable $promisesOrValues): PromiseInterface
@@ -77,6 +77,7 @@ function all(iterable $promisesOrValues): PromiseInterface
7777

7878
return new Promise(function ($resolve, $reject) use ($promisesOrValues, $cancellationQueue): void {
7979
$toResolve = 0;
80+
/** @var bool */
8081
$continue = true;
8182
$values = [];
8283

@@ -118,7 +119,7 @@ function (\Throwable $reason) use (&$continue, $reject): void {
118119
* The returned promise will become **infinitely pending** if `$promisesOrValues`
119120
* contains 0 items.
120121
*
121-
* @param iterable $promisesOrValues
122+
* @param iterable<mixed> $promisesOrValues
122123
* @return PromiseInterface
123124
*/
124125
function race(iterable $promisesOrValues): PromiseInterface
@@ -153,7 +154,7 @@ function race(iterable $promisesOrValues): PromiseInterface
153154
* The returned promise will also reject with a `React\Promise\Exception\LengthException`
154155
* if `$promisesOrValues` contains 0 items.
155156
*
156-
* @param iterable $promisesOrValues
157+
* @param iterable<mixed> $promisesOrValues
157158
* @return PromiseInterface
158159
*/
159160
function any(iterable $promisesOrValues): PromiseInterface
@@ -215,6 +216,7 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool
215216
} elseif (\is_object($callback) && !$callback instanceof \Closure) {
216217
$callbackReflection = new \ReflectionMethod($callback, '__invoke');
217218
} else {
219+
assert($callback instanceof \Closure || \is_string($callback));
218220
$callbackReflection = new \ReflectionFunction($callback);
219221
}
220222

@@ -257,16 +259,16 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool
257259
if ($type instanceof \ReflectionIntersectionType) {
258260
foreach ($type->getTypes() as $typeToMatch) {
259261
assert($typeToMatch instanceof \ReflectionNamedType);
260-
if (!($matches = ($typeToMatch->isBuiltin() && \gettype($reason) === $typeToMatch->getName())
261-
|| (new \ReflectionClass($typeToMatch->getName()))->isInstance($reason))) {
262+
$name = $typeToMatch->getName();
263+
if (!($matches = (!$typeToMatch->isBuiltin() && $reason instanceof $name))) {
262264
break;
263265
}
264266
}
265267
assert(isset($matches));
266268
} else {
267269
assert($type instanceof \ReflectionNamedType);
268-
$matches = ($type->isBuiltin() && \gettype($reason) === $type->getName())
269-
|| (new \ReflectionClass($type->getName()))->isInstance($reason);
270+
$name = $type->getName();
271+
$matches = !$type->isBuiltin() && $reason instanceof $name;
270272
}
271273

272274
// If we look for a single match (union), we can return early on match

tests/DeferredTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class DeferredTest extends TestCase
88
{
99
use PromiseTest\FullTestTrait;
1010

11-
public function getPromiseTestAdapter(callable $canceller = null)
11+
public function getPromiseTestAdapter(callable $canceller = null): CallbackPromiseAdapter
1212
{
1313
$d = new Deferred($canceller);
1414

@@ -21,7 +21,7 @@ public function getPromiseTestAdapter(callable $canceller = null)
2121
}
2222

2323
/** @test */
24-
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException()
24+
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException(): void
2525
{
2626
gc_collect_cycles();
2727
$deferred = new Deferred(function ($resolve, $reject) {
@@ -34,7 +34,7 @@ public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithEx
3434
}
3535

3636
/** @test */
37-
public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejectsWithException()
37+
public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejectsWithException(): void
3838
{
3939
gc_collect_cycles();
4040
gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on
@@ -49,7 +49,7 @@ public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejects
4949
}
5050

5151
/** @test */
52-
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndExplicitlyRejectWithException()
52+
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndExplicitlyRejectWithException(): void
5353
{
5454
gc_collect_cycles();
5555
gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on

0 commit comments

Comments
 (0)