Skip to content

Commit 4172f6e

Browse files
committed
Improve PHP 8.4+ support by avoiding implicitly nullable types
1 parent f7ebf4e commit 4172f6e

File tree

5 files changed

+84
-6
lines changed

5 files changed

+84
-6
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"clue/term-react": "^1.0 || ^0.1.1",
1616
"clue/utf8-react": "^1.0 || ^0.1",
1717
"react/event-loop": "^1.2",
18-
"react/stream": "^1.2"
18+
"react/stream": "^1.4"
1919
},
2020
"require-dev": {
2121
"clue/arguments": "^2.0",

src/Readline.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ class Readline extends EventEmitter implements ReadableStreamInterface
3737
private $autocomplete = null;
3838
private $autocompleteSuggestions = 8;
3939

40-
public function __construct(ReadableStreamInterface $input, WritableStreamInterface $output, EventEmitterInterface $base = null)
40+
/**
41+
* @param ReadableStreamInterface $input
42+
* @param WritableStreamInterface $output
43+
* @param ?EventEmitterInterface $base
44+
*/
45+
public function __construct(ReadableStreamInterface $input, WritableStreamInterface $output, $base = null)
4146
{
4247
$this->input = $input;
4348
$this->output = $output;
@@ -49,6 +54,10 @@ public function __construct(ReadableStreamInterface $input, WritableStreamInterf
4954
// push input through control code parser
5055
$parser = new ControlCodeParser($input);
5156

57+
if ($base !== null && !$base instanceof EventEmitterInterface) { // manual type check to support legacy PHP < 7.1
58+
throw new \InvalidArgumentException('Argument #3 ($base) expected null|Evenement\EventEmitterInterface');
59+
}
60+
5261
$that = $this;
5362
$codes = array(
5463
"\n" => 'onKeyEnter', // ^J
@@ -778,9 +787,11 @@ public function onKeyDown()
778787
/**
779788
* Will be invoked for character(s) that could not otherwise be processed by the sequencer
780789
*
790+
* @param string $chars
791+
* @param ?EventEmitterInterface $base
781792
* @internal
782793
*/
783-
public function onFallback($chars, EventEmitterInterface $base = null)
794+
public function onFallback($chars, $base = null)
784795
{
785796
// check if there's any special key binding for any of the chars
786797
$buffer = '';

src/Stdio.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,24 @@ class Stdio extends EventEmitter implements DuplexStreamInterface
3535
* @param ?WritableStreamInterface $output
3636
* @param ?Readline $readline
3737
*/
38-
public function __construct(LoopInterface $loop = null, ReadableStreamInterface $input = null, WritableStreamInterface $output = null, Readline $readline = null)
38+
public function __construct($loop = null, $input = null, $output = null, $readline = null)
3939
{
40+
if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1
41+
throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface');
42+
}
43+
44+
if ($input !== null && !$input instanceof ReadableStreamInterface) { // manual type check to support legacy PHP < 7.1
45+
throw new \InvalidArgumentException('Argument #2 ($input) expected null|React\Stream\ReadableStreamInterface');
46+
}
47+
48+
if ($output !== null && !$output instanceof WritableStreamInterface) { // manual type check to support legacy PHP < 7.1
49+
throw new \InvalidArgumentException('Argument #3 ($output) expected null|React\Stream\WritableStreamInterface');
50+
}
51+
52+
if ($readline !== null && !$readline instanceof Readline) { // manual type check to support legacy PHP < 7.1
53+
throw new \InvalidArgumentException('Argument #4 ($readline) expected null|Clue\React\Stdio\Readline');
54+
}
55+
4056
if ($input === null) {
4157
$input = $this->createStdin($loop); // @codeCoverageIgnore
4258
}
@@ -546,7 +562,7 @@ private function restoreTtyMode()
546562
* @return ReadableStreamInterface
547563
* @codeCoverageIgnore this is covered by functional tests with/without ext-readline
548564
*/
549-
private function createStdin(LoopInterface $loop = null)
565+
private function createStdin($loop = null)
550566
{
551567
// STDIN not defined ("php -a") or already closed (`fclose(STDIN)`)
552568
// also support starting program with closed STDIN ("example.php 0<&-")
@@ -586,7 +602,7 @@ private function createStdin(LoopInterface $loop = null)
586602
* @return WritableStreamInterface
587603
* @codeCoverageIgnore this is covered by functional tests
588604
*/
589-
private function createStdout(LoopInterface $loop = null)
605+
private function createStdout($loop = null)
590606
{
591607
// STDOUT not defined ("php -a") or already closed (`fclose(STDOUT)`)
592608
// also support starting program with closed STDOUT ("example.php >&-")

tests/ReadlineTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public function setUpReadline()
2323
$this->readline = new Readline($this->input, $this->output);
2424
}
2525

26+
public function testCtorThrowsExceptionForInvalidBase()
27+
{
28+
$this->setExpectedException('InvalidArgumentException', 'Argument #3 ($base) expected null|Evenement\EventEmitterInterface');
29+
new Readline($this->input, $this->output, 'invalid');
30+
}
31+
2632
public function testSettersReturnSelf()
2733
{
2834
$this->assertSame($this->readline, $this->readline->setEcho(true));

tests/StdioTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,51 @@ public function testCtorReadlineArgWillBeReturnedBygetReadline()
5353
$this->assertSame($readline, $stdio->getReadline());
5454
}
5555

56+
public function testCtorThrowsExceptionForInvalidLoop()
57+
{
58+
$input = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
59+
$output = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
60+
61+
//$readline = $this->getMockBuilder('Clue\React\Stdio\Readline')->disableOriginalConstructor()->getMock();
62+
$readline = new Readline($input, $output);
63+
64+
$this->setExpectedException('InvalidArgumentException', 'Argument #1 ($loop) expected null|React\EventLoop\LoopInterface');
65+
new Stdio('invalid', $input, $output, $readline);
66+
}
67+
68+
public function testCtorThrowsExceptionForInvalidInput()
69+
{
70+
$input = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
71+
$output = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
72+
73+
//$readline = $this->getMockBuilder('Clue\React\Stdio\Readline')->disableOriginalConstructor()->getMock();
74+
$readline = new Readline($input, $output);
75+
76+
$this->setExpectedException('InvalidArgumentException', 'Argument #2 ($input) expected null|React\Stream\ReadableStreamInterface');
77+
new Stdio($this->loop, 'invalid', $output, $readline);
78+
}
79+
80+
public function testCtorThrowsExceptionForInvalidOutput()
81+
{
82+
$input = $input = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
83+
$output = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
84+
85+
//$readline = $this->getMockBuilder('Clue\React\Stdio\Readline')->disableOriginalConstructor()->getMock();
86+
$readline = new Readline($input, $output);
87+
88+
$this->setExpectedException('InvalidArgumentException', 'Argument #3 ($output) expected null|React\Stream\WritableStreamInterface');
89+
new Stdio($this->loop, $input, 'invalid', $readline);
90+
}
91+
92+
public function testCtorThrowsExceptionForInvalidReadline()
93+
{
94+
$input = $input = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
95+
$output = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
96+
97+
$this->setExpectedException('InvalidArgumentException', 'Argument #4 ($readline) expected null|Clue\React\Stdio\Readline');
98+
new Stdio($this->loop, $input, $output, 'invalid');
99+
}
100+
56101
public function testWriteEmptyStringWillNotWriteToOutput()
57102
{
58103
$input = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();

0 commit comments

Comments
 (0)