Skip to content

Commit

Permalink
Merge pull request #70 from clue-labs/nullable
Browse files Browse the repository at this point in the history
Improve PHP 8.4+ support by avoiding implicitly nullable types
  • Loading branch information
WyriHaximus committed May 24, 2024
2 parents 625f497 + 83a133d commit b7b84ee
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 7 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"require": {
"php": ">=5.3",
"react/event-loop": "^1.2",
"react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
"react/promise": "^3.2 || ^2.7.0 || ^1.2.1"
},
"require-dev": {
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
Expand Down
20 changes: 14 additions & 6 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,12 @@
* @param ?LoopInterface $loop
* @return PromiseInterface<T>
*/
function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null)
function timeout(PromiseInterface $promise, $time, $loop = null)
{
if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
}

// cancelling this promise will only try to cancel the input promise,
// thus leaving responsibility to the input promise.
$canceller = null;
Expand Down Expand Up @@ -222,8 +226,12 @@ function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null)
* @param ?LoopInterface $loop
* @return PromiseInterface<void>
*/
function sleep($time, LoopInterface $loop = null)
function sleep($time, $loop = null)
{
if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
}

if ($loop === null) {
$loop = Loop::get();
}
Expand Down Expand Up @@ -280,7 +288,7 @@ function sleep($time, LoopInterface $loop = null)
* @deprecated 1.8.0 See `sleep()` instead
* @see sleep()
*/
function resolve($time, LoopInterface $loop = null)
function resolve($time, $loop = null)
{
return sleep($time, $loop)->then(function() use ($time) {
return $time;
Expand Down Expand Up @@ -317,13 +325,13 @@ function resolve($time, LoopInterface $loop = null)
* $timer->cancel();
* ```
*
* @param float $time
* @param LoopInterface $loop
* @param float $time
* @param ?LoopInterface $loop
* @return PromiseInterface<never>
* @deprecated 1.8.0 See `sleep()` instead
* @see sleep()
*/
function reject($time, LoopInterface $loop = null)
function reject($time, $loop = null)
{
return sleep($time, $loop)->then(function () use ($time) {
throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');
Expand Down
6 changes: 6 additions & 0 deletions tests/FunctionRejectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public function testCancellingPromiseWillRejectTimer()
$this->expectPromiseRejected($promise);
}

public function testRejectWithInvalidLoopThrows()
{
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
Timer\reject(1.0, 42);
}

public function testWaitingForPromiseToRejectDoesNotLeaveGarbageCycles()
{
if (class_exists('React\Promise\When')) {
Expand Down
6 changes: 6 additions & 0 deletions tests/FunctionResolveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public function testCancellingPromiseWillRejectTimer()
$this->expectPromiseRejected($promise);
}

public function testResolveWithInvalidLoopThrows()
{
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
Timer\resolve(1.0, 42);
}

public function testWaitingForPromiseToResolveDoesNotLeaveGarbageCycles()
{
if (class_exists('React\Promise\When')) {
Expand Down
6 changes: 6 additions & 0 deletions tests/FunctionSleepTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public function testCancellingPromiseWillRejectTimer()
$this->expectPromiseRejected($promise);
}

public function testSleepWithInvalidLoopThrows()
{
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
Timer\sleep(1.0, 42);
}

public function testWaitingForPromiseToResolveDoesNotLeaveGarbageCycles()
{
if (class_exists('React\Promise\When')) {
Expand Down
6 changes: 6 additions & 0 deletions tests/FunctionTimeoutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ public function testCancelTimeoutWillResolveIfGivenPromiseWillResolve()
$this->expectPromiseResolved($timeout);
}

public function testTimeoutWithInvalidLoopThrows()
{
$this->setExpectedException('InvalidArgumentException', 'Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
Timer\timeout(Promise\resolve(null), 1.0, 42);
}

public function testWaitingForPromiseToResolveBeforeTimeoutDoesNotLeaveGarbageCycles()
{
if (class_exists('React\Promise\When')) {
Expand Down
15 changes: 15 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ protected function createCallableMock()
}
}

public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null)
{
if (method_exists($this, 'expectException')) {
// PHPUnit 5+
$this->expectException($exception);
$this->expectExceptionMessage($exceptionMessage);
if ($exceptionCode !== null) {
$this->expectExceptionCode($exceptionCode);
}
} else {
// legacy PHPUnit
parent::setExpectedException($exception, $exceptionMessage, $exceptionCode);
}
}

protected function expectPromiseRejected($promise)
{
return $promise->then($this->expectCallableNever(), $this->expectCallableOnce());
Expand Down

0 comments on commit b7b84ee

Please sign in to comment.