Skip to content

Commit

Permalink
Improve type definitions and update to PHPStan level max
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Jun 21, 2023
1 parent fd5e886 commit c4e6145
Show file tree
Hide file tree
Showing 39 changed files with 317 additions and 326 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ To run the test suite, go to the project root and run:
vendor/bin/phpunit
```

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

```bash
vendor/bin/phpstan
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
level: 3
level: max

paths:
- src/
Expand Down
8 changes: 8 additions & 0 deletions src/Deferred.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

final class Deferred
{
/** @var Promise */
private $promise;

/** @var callable */
private $resolveCallback;

/** @var callable */
private $rejectCallback;

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

/**
* @param mixed $value
*/
public function resolve($value): void
{
($this->resolveCallback)($value);
Expand Down
4 changes: 3 additions & 1 deletion src/Exception/CompositeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
*/
class CompositeException extends \Exception
{
/** @var \Throwable[] */
private $throwables;

public function __construct(array $throwables, $message = '', $code = 0, $previous = null)
/** @param \Throwable[] $throwables */
public function __construct(array $throwables, string $message = '', int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);

Expand Down
7 changes: 7 additions & 0 deletions src/Internal/CancellationQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
*/
final class CancellationQueue
{
/** @var bool */
private $started = false;

/** @var object[] */
private $queue = [];

public function __invoke(): void
Expand All @@ -20,6 +23,9 @@ public function __invoke(): void
$this->drain();
}

/**
* @param mixed $cancellable
*/
public function enqueue($cancellable): void
{
if (!\is_object($cancellable) || !\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) {
Expand All @@ -37,6 +43,7 @@ private function drain(): void
{
for ($i = \key($this->queue); isset($this->queue[$i]); $i++) {
$cancellable = $this->queue[$i];
assert(\method_exists($cancellable, 'cancel'));

$exception = null;

Expand Down
5 changes: 5 additions & 0 deletions src/Internal/FulfilledPromise.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
*/
final class FulfilledPromise implements PromiseInterface
{
/** @var mixed */
private $value;

/**
* @param mixed $value
* @throws \InvalidArgumentException
*/
public function __construct($value = null)
{
if ($value instanceof PromiseInterface) {
Expand Down
4 changes: 4 additions & 0 deletions src/Internal/RejectedPromise.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
*/
final class RejectedPromise implements PromiseInterface
{
/** @var \Throwable */
private $reason;

/**
* @param \Throwable $reason
*/
public function __construct(\Throwable $reason)
{
$this->reason = $reason;
Expand Down
9 changes: 8 additions & 1 deletion src/Promise.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@

final class Promise implements PromiseInterface
{
/** @var ?callable */
private $canceller;

/** @var ?PromiseInterface */
private $result;

/** @var callable[] */
private $handlers = [];

/** @var int */
private $requiredCancelRequests = 0;

public function __construct(callable $resolver, callable $canceller = null)
Expand Down Expand Up @@ -46,6 +51,7 @@ public function then(callable $onFulfilled = null, callable $onRejected = null):
return new static(
$this->resolver($onFulfilled, $onRejected),
static function () use (&$parent) {
assert($parent instanceof self);
--$parent->requiredCancelRequests;

if ($parent->requiredCancelRequests <= 0) {
Expand Down Expand Up @@ -187,7 +193,7 @@ private function settle(PromiseInterface $result): void
}
}

private function unwrap($promise): PromiseInterface
private function unwrap(PromiseInterface $promise): PromiseInterface
{
while ($promise instanceof self && null !== $promise->result) {
$promise = $promise->result;
Expand All @@ -213,6 +219,7 @@ private function call(callable $cb): void
} elseif (\is_object($callback) && !$callback instanceof \Closure) {
$ref = new \ReflectionMethod($callback, '__invoke');
} else {
assert($callback instanceof \Closure || \is_string($callback));
$ref = new \ReflectionFunction($callback);
}
$args = $ref->getNumberOfParameters();
Expand Down
16 changes: 9 additions & 7 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function reject(\Throwable $reason): PromiseInterface
* will be an array containing the resolution values of each of the items in
* `$promisesOrValues`.
*
* @param iterable $promisesOrValues
* @param iterable<mixed> $promisesOrValues
* @return PromiseInterface
*/
function all(iterable $promisesOrValues): PromiseInterface
Expand All @@ -77,6 +77,7 @@ function all(iterable $promisesOrValues): PromiseInterface

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

Expand Down Expand Up @@ -118,7 +119,7 @@ function (\Throwable $reason) use (&$continue, $reject): void {
* The returned promise will become **infinitely pending** if `$promisesOrValues`
* contains 0 items.
*
* @param iterable $promisesOrValues
* @param iterable<mixed> $promisesOrValues
* @return PromiseInterface
*/
function race(iterable $promisesOrValues): PromiseInterface
Expand Down Expand Up @@ -153,7 +154,7 @@ function race(iterable $promisesOrValues): PromiseInterface
* The returned promise will also reject with a `React\Promise\Exception\LengthException`
* if `$promisesOrValues` contains 0 items.
*
* @param iterable $promisesOrValues
* @param iterable<mixed> $promisesOrValues
* @return PromiseInterface
*/
function any(iterable $promisesOrValues): PromiseInterface
Expand Down Expand Up @@ -215,6 +216,7 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool
} elseif (\is_object($callback) && !$callback instanceof \Closure) {
$callbackReflection = new \ReflectionMethod($callback, '__invoke');
} else {
assert($callback instanceof \Closure || \is_string($callback));
$callbackReflection = new \ReflectionFunction($callback);
}

Expand Down Expand Up @@ -257,16 +259,16 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool
if ($type instanceof \ReflectionIntersectionType) {
foreach ($type->getTypes() as $typeToMatch) {
assert($typeToMatch instanceof \ReflectionNamedType);
if (!($matches = ($typeToMatch->isBuiltin() && \gettype($reason) === $typeToMatch->getName())
|| (new \ReflectionClass($typeToMatch->getName()))->isInstance($reason))) {
$name = $typeToMatch->getName();
if (!($matches = (!$typeToMatch->isBuiltin() && $reason instanceof $name))) {
break;
}
}
assert(isset($matches));
} else {
assert($type instanceof \ReflectionNamedType);
$matches = ($type->isBuiltin() && \gettype($reason) === $type->getName())
|| (new \ReflectionClass($type->getName()))->isInstance($reason);
$name = $type->getName();
$matches = !$type->isBuiltin() && $reason instanceof $name;
}

// If we look for a single match (union), we can return early on match
Expand Down
8 changes: 4 additions & 4 deletions tests/DeferredTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class DeferredTest extends TestCase
{
use PromiseTest\FullTestTrait;

public function getPromiseTestAdapter(callable $canceller = null)
public function getPromiseTestAdapter(callable $canceller = null): CallbackPromiseAdapter
{
$d = new Deferred($canceller);

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

/** @test */
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException()
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException(): void
{
gc_collect_cycles();
$deferred = new Deferred(function ($resolve, $reject) {
Expand All @@ -34,7 +34,7 @@ public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithEx
}

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

/** @test */
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndExplicitlyRejectWithException()
public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndExplicitlyRejectWithException(): void
{
gc_collect_cycles();
gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on
Expand Down
20 changes: 10 additions & 10 deletions tests/FunctionAllTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class FunctionAllTest extends TestCase
{
/** @test */
public function shouldResolveEmptyInput()
public function shouldResolveEmptyInput(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -20,7 +20,7 @@ public function shouldResolveEmptyInput()
}

/** @test */
public function shouldResolveValuesArray()
public function shouldResolveValuesArray(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -33,7 +33,7 @@ public function shouldResolveValuesArray()
}

/** @test */
public function shouldResolvePromisesArray()
public function shouldResolvePromisesArray(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -46,7 +46,7 @@ public function shouldResolvePromisesArray()
}

/** @test */
public function shouldResolveSparseArrayInput()
public function shouldResolveSparseArrayInput(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -59,7 +59,7 @@ public function shouldResolveSparseArrayInput()
}

/** @test */
public function shouldResolveValuesGenerator()
public function shouldResolveValuesGenerator(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -77,7 +77,7 @@ public function shouldResolveValuesGenerator()
}

/** @test */
public function shouldResolveValuesGeneratorEmpty()
public function shouldResolveValuesGeneratorEmpty(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -86,7 +86,7 @@ public function shouldResolveValuesGeneratorEmpty()
->with(self::identicalTo([]));

$gen = (function () {
if (false) {
if (false) { // @phpstan-ignore-line
yield;
}
})();
Expand All @@ -95,7 +95,7 @@ public function shouldResolveValuesGeneratorEmpty()
}

/** @test */
public function shouldRejectIfAnyInputPromiseRejects()
public function shouldRejectIfAnyInputPromiseRejects(): void
{
$exception2 = new Exception();
$exception3 = new Exception();
Expand All @@ -111,7 +111,7 @@ public function shouldRejectIfAnyInputPromiseRejects()
}

/** @test */
public function shouldRejectInfiteGeneratorOrRejectedPromises()
public function shouldRejectInfiteGeneratorOrRejectedPromises(): void
{
$mock = $this->createCallableMock();
$mock
Expand All @@ -129,7 +129,7 @@ public function shouldRejectInfiteGeneratorOrRejectedPromises()
}

/** @test */
public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises()
public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises(): void
{
$mock = $this->createCallableMock();
$mock
Expand Down
Loading

0 comments on commit c4e6145

Please sign in to comment.