Skip to content

Commit b7b84ee

Browse files
authored
Merge pull request #70 from clue-labs/nullable
Improve PHP 8.4+ support by avoiding implicitly nullable types
2 parents 625f497 + 83a133d commit b7b84ee

7 files changed

+54
-7
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"require": {
3030
"php": ">=5.3",
3131
"react/event-loop": "^1.2",
32-
"react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
32+
"react/promise": "^3.2 || ^2.7.0 || ^1.2.1"
3333
},
3434
"require-dev": {
3535
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"

src/functions.php

+14-6
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,12 @@
135135
* @param ?LoopInterface $loop
136136
* @return PromiseInterface<T>
137137
*/
138-
function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null)
138+
function timeout(PromiseInterface $promise, $time, $loop = null)
139139
{
140+
if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
141+
throw new \InvalidArgumentException('Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
142+
}
143+
140144
// cancelling this promise will only try to cancel the input promise,
141145
// thus leaving responsibility to the input promise.
142146
$canceller = null;
@@ -222,8 +226,12 @@ function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null)
222226
* @param ?LoopInterface $loop
223227
* @return PromiseInterface<void>
224228
*/
225-
function sleep($time, LoopInterface $loop = null)
229+
function sleep($time, $loop = null)
226230
{
231+
if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
232+
throw new \InvalidArgumentException('Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
233+
}
234+
227235
if ($loop === null) {
228236
$loop = Loop::get();
229237
}
@@ -280,7 +288,7 @@ function sleep($time, LoopInterface $loop = null)
280288
* @deprecated 1.8.0 See `sleep()` instead
281289
* @see sleep()
282290
*/
283-
function resolve($time, LoopInterface $loop = null)
291+
function resolve($time, $loop = null)
284292
{
285293
return sleep($time, $loop)->then(function() use ($time) {
286294
return $time;
@@ -317,13 +325,13 @@ function resolve($time, LoopInterface $loop = null)
317325
* $timer->cancel();
318326
* ```
319327
*
320-
* @param float $time
321-
* @param LoopInterface $loop
328+
* @param float $time
329+
* @param ?LoopInterface $loop
322330
* @return PromiseInterface<never>
323331
* @deprecated 1.8.0 See `sleep()` instead
324332
* @see sleep()
325333
*/
326-
function reject($time, LoopInterface $loop = null)
334+
function reject($time, $loop = null)
327335
{
328336
return sleep($time, $loop)->then(function () use ($time) {
329337
throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');

tests/FunctionRejectTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ public function testCancellingPromiseWillRejectTimer()
4848
$this->expectPromiseRejected($promise);
4949
}
5050

51+
public function testRejectWithInvalidLoopThrows()
52+
{
53+
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
54+
Timer\reject(1.0, 42);
55+
}
56+
5157
public function testWaitingForPromiseToRejectDoesNotLeaveGarbageCycles()
5258
{
5359
if (class_exists('React\Promise\When')) {

tests/FunctionResolveTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public function testCancellingPromiseWillRejectTimer()
7070
$this->expectPromiseRejected($promise);
7171
}
7272

73+
public function testResolveWithInvalidLoopThrows()
74+
{
75+
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
76+
Timer\resolve(1.0, 42);
77+
}
78+
7379
public function testWaitingForPromiseToResolveDoesNotLeaveGarbageCycles()
7480
{
7581
if (class_exists('React\Promise\When')) {

tests/FunctionSleepTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public function testCancellingPromiseWillRejectTimer()
7070
$this->expectPromiseRejected($promise);
7171
}
7272

73+
public function testSleepWithInvalidLoopThrows()
74+
{
75+
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($loop) expected null|React\EventLoop\LoopInterface');
76+
Timer\sleep(1.0, 42);
77+
}
78+
7379
public function testWaitingForPromiseToResolveDoesNotLeaveGarbageCycles()
7480
{
7581
if (class_exists('React\Promise\When')) {

tests/FunctionTimeoutTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ public function testCancelTimeoutWillResolveIfGivenPromiseWillResolve()
184184
$this->expectPromiseResolved($timeout);
185185
}
186186

187+
public function testTimeoutWithInvalidLoopThrows()
188+
{
189+
$this->setExpectedException('InvalidArgumentException', 'Argument #3 ($loop) expected null|React\EventLoop\LoopInterface');
190+
Timer\timeout(Promise\resolve(null), 1.0, 42);
191+
}
192+
187193
public function testWaitingForPromiseToResolveBeforeTimeoutDoesNotLeaveGarbageCycles()
188194
{
189195
if (class_exists('React\Promise\When')) {

tests/TestCase.php

+15
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ protected function createCallableMock()
4242
}
4343
}
4444

45+
public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null)
46+
{
47+
if (method_exists($this, 'expectException')) {
48+
// PHPUnit 5+
49+
$this->expectException($exception);
50+
$this->expectExceptionMessage($exceptionMessage);
51+
if ($exceptionCode !== null) {
52+
$this->expectExceptionCode($exceptionCode);
53+
}
54+
} else {
55+
// legacy PHPUnit
56+
parent::setExpectedException($exception, $exceptionMessage, $exceptionCode);
57+
}
58+
}
59+
4560
protected function expectPromiseRejected($promise)
4661
{
4762
return $promise->then($this->expectCallableNever(), $this->expectCallableOnce());

0 commit comments

Comments
 (0)