diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4bcf71..8555965 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,7 @@ jobs: strategy: matrix: php: + - 8.4 - 8.3 - 8.2 - 8.1 diff --git a/composer.json b/composer.json index 9299d77..75a3141 100644 --- a/composer.json +++ b/composer.json @@ -14,12 +14,12 @@ "php": ">=5.3", "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "react/event-loop": "^1.2", - "react/promise": "^3.0 || ^2.9 || ^1.1", - "react/socket": "^1.14" + "react/promise": "^3.2 || ^2.9 || ^1.1", + "react/socket": "^1.16" }, "require-dev": { "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4.2 || ^3.2 || ^2.2" + "react/async": "^4.3 || ^3.2 || ^2.2" }, "autoload": { "psr-4": { diff --git a/src/Client.php b/src/Client.php index 98307cd..ffc2aa6 100644 --- a/src/Client.php +++ b/src/Client.php @@ -33,8 +33,16 @@ class Client extends EventEmitter private $actionId = 0; - public function __construct(ConnectionInterface $stream, Parser $parser = null) + /** + * @param ConnectionInterface $stream + * @param ?Parser $parser + */ + public function __construct(ConnectionInterface $stream, $parser = null) { + if ($parser !== null && !$parser instanceof Parser) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($parser) expected null|Clue\React\Ami\Protocol\Parser'); + } + if ($parser === null) { $parser = new Parser(); } diff --git a/src/Factory.php b/src/Factory.php index 1169a27..b8ee591 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -43,8 +43,19 @@ class Factory { private $connector; - public function __construct(LoopInterface $loop = null, ConnectorInterface $connector = null) + /** + * @param ?LoopInterface $loop + * @param ?ConnectorInterface $connector + */ + public function __construct($loop = null, $connector = null) { + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface'); + } + if ($connector !== null && !$connector instanceof ConnectorInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($connector) expected null|React\Socket\ConnectorInterface'); + } + if ($connector === null) { $connector = new Connector(array(), $loop); } diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 44ce726..4b93506 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -43,6 +43,12 @@ public function testUnexpectedResponseEmitsErrorAndClosesClient() $client->handleMessage(new Response(array('ActionID' => 1))); } + public function testCtorThrowsForInvalidParser() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($parser) expected null|Clue\React\Ami\Protocol\Parser'); + new Client($this->createStreamMock(), 'parser'); + } + private function createStreamMock() { if (method_exists('PHPUnit\Framework\MockObject\MockBuilder', 'onlyMethods')) { diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php index 2fe2ff7..607c899 100644 --- a/tests/FactoryTest.php +++ b/tests/FactoryTest.php @@ -31,6 +31,18 @@ public function testDefaultCtorCreatesConnectorAutomatically() $this->assertInstanceOf('React\Socket\Connector', $connector); } + public function testCtorThrowsForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #1 ($loop) expected null|React\EventLoop\LoopInterface'); + new Factory('loop'); + } + + public function testCtorThrowsForInvalidConnector() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($connector) expected null|React\Socket\ConnectorInterface'); + new Factory(null, 'connector'); + } + public function testCreateClientUsesDefaultPortForTcpConnection() { $promise = new Promise(function () { });