diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index ee78d555..b3370342 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -10,7 +10,7 @@ on: jobs: php-cs-fixer: - name: linter + name: PHP CS Fixer runs-on: ubuntu-latest steps: @@ -19,10 +19,44 @@ jobs: uses: actions/checkout@v3 - name: Setup PHP with Composer and extensions + uses: shivammathur/setup-php@v2 with: php-version: 8.1 tools: php-cs-fixer - uses: shivammathur/setup-php@v2 - name: Run php-cs-fixer run: php-cs-fixer fix --diff --dry-run --allow-risky=yes --using-cache=no + + phpstan: + name: PHPStan + runs-on: ubuntu-latest + + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PHP with Composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + tools: phpstan + + - name: Get Composer cache directory + id: composer-cache + run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.directory }} + key: tests-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: tests-php-${{ matrix.php }}-composer + + - name: Install Composer dependencies + env: + PHP_VERSION: ${{ matrix.php }} + run: composer install --ansi --no-progress --prefer-dist $(if [ "$PHP_VERSION" == "8.0" ]; then echo "--ignore-platform-reqs"; fi;) + + - name: Run PHPStan + run: phpstan analyse diff --git a/phpstan.dist.neon b/phpstan.dist.neon new file mode 100644 index 00000000..c0603cff --- /dev/null +++ b/phpstan.dist.neon @@ -0,0 +1,25 @@ +parameters: + level: 0 + + paths: + - src + - tests + + ignoreErrors: + - '#^Function phpiredis_\w+ not found\.$#' + - + message: "#^Unsafe usage of new static\\(\\)\\.$#" + count: 3 + path: src/Client.php + - + message: "#^Unsafe usage of new static\\(\\)\\.$#" + count: 1 + path: src/Connection/Parameters.php + - + message: "#^Static method Predis\\\\Command\\\\RawCommand\\:\\:create\\(\\) invoked with 0 parameters, at least 1 required\\.$#" + count: 1 + path: tests/Predis/Command/RawCommandTest.php + - + message: "#^Call to an undefined method Predis\\\\Configuration\\\\Option\\\\AggregateTest\\:\\:getMockConnectionClass\\(\\)\\.$#" + count: 2 + path: tests/Predis/Configuration/Option/AggregateTest.php diff --git a/src/Cluster/SlotMap.php b/src/Cluster/SlotMap.php index 5ed0d3e6..5ca1896b 100644 --- a/src/Cluster/SlotMap.php +++ b/src/Cluster/SlotMap.php @@ -17,6 +17,7 @@ use ArrayIterator; use Countable; use IteratorAggregate; use OutOfBoundsException; +use Predis\Connection\NodeConnectionInterface; use ReturnTypeWillChange; /** @@ -144,7 +145,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable * * @param int $slot Slot index. * - * @return string + * @return ?string */ #[ReturnTypeWillChange] public function offsetGet($slot) @@ -152,6 +153,8 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable if (isset($this->slots[$slot])) { return $this->slots[$slot]; } + + return null; } /** @@ -159,8 +162,6 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable * * @param int $slot Slot index. * @param NodeConnectionInterface|string $connection ID or connection instance. - * - * @return string */ #[ReturnTypeWillChange] public function offsetSet($slot, $connection) @@ -176,8 +177,6 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable * Returns the node assigned to the specified slot. * * @param int $slot Slot index. - * - * @return string */ #[ReturnTypeWillChange] public function offsetUnset($slot) diff --git a/src/Cluster/StrategyInterface.php b/src/Cluster/StrategyInterface.php index 9cfbc269..83801ae6 100644 --- a/src/Cluster/StrategyInterface.php +++ b/src/Cluster/StrategyInterface.php @@ -29,7 +29,7 @@ interface StrategyInterface * * @param CommandInterface $command Command instance. * - * @return int + * @return int|null */ public function getSlot(CommandInterface $command); @@ -39,7 +39,7 @@ interface StrategyInterface * * @param string $key Key string. * - * @return int + * @return int|null */ public function getSlotByKey($key); diff --git a/src/Command/Factory.php b/src/Command/Factory.php index 75433392..c0b7745d 100644 --- a/src/Command/Factory.php +++ b/src/Command/Factory.php @@ -56,6 +56,8 @@ abstract class Factory implements FactoryInterface if (isset($this->commands[$commandID = strtoupper($commandID)])) { return $this->commands[$commandID]; } + + return null; } /** diff --git a/src/Configuration/Option/Replication.php b/src/Configuration/Option/Replication.php index f9353201..00aa9741 100644 --- a/src/Configuration/Option/Replication.php +++ b/src/Configuration/Option/Replication.php @@ -68,12 +68,12 @@ class Replication extends Aggregate switch ($description) { case 'sentinel': case 'redis-sentinel': - return function ($parameters, $options, $option) { + return function ($parameters, $options) { return new SentinelReplication($options->service, $parameters, $options->connections); }; case 'predis': - return $this->getDefaultConnectionInitializer($options); + return $this->getDefaultConnectionInitializer(); default: throw new InvalidArgumentException(sprintf( @@ -91,7 +91,7 @@ class Replication extends Aggregate */ protected function getDefaultConnectionInitializer() { - return function ($parameters, $options, $option) { + return function ($parameters, $options) { $connection = new MasterSlaveReplication(); if ($options->autodiscovery) { diff --git a/src/Connection/PhpiredisSocketConnection.php b/src/Connection/PhpiredisSocketConnection.php index 26a9b4af..c84b5bee 100644 --- a/src/Connection/PhpiredisSocketConnection.php +++ b/src/Connection/PhpiredisSocketConnection.php @@ -283,7 +283,7 @@ class PhpiredisSocketConnection extends AbstractConnection * @param string $address IP address (DNS-resolved from hostname) * @param ParametersInterface $parameters Parameters used to initialize the connection. * - * @return string + * @return void */ private function connectWithTimeout($socket, $address, ParametersInterface $parameters) { diff --git a/src/Connection/Replication/MasterSlaveReplication.php b/src/Connection/Replication/MasterSlaveReplication.php index 613a0581..39142c10 100644 --- a/src/Connection/Replication/MasterSlaveReplication.php +++ b/src/Connection/Replication/MasterSlaveReplication.php @@ -221,6 +221,8 @@ class MasterSlaveReplication implements ReplicationInterface } elseif ($role === 'slave') { return $this->pickSlave(); } + + return null; } /** @@ -316,13 +318,15 @@ class MasterSlaveReplication implements ReplicationInterface /** * Returns a random slave. * - * @return NodeConnectionInterface + * @return ?NodeConnectionInterface */ protected function pickSlave() { if ($this->slaves) { return $this->slaves[array_rand($this->slaves)]; } + + return null; } /** diff --git a/tests/Predis/Collection/Iterator/HashKeyTest.php b/tests/Predis/Collection/Iterator/HashKeyTest.php index bc0b8b99..4a8c0d5e 100644 --- a/tests/Predis/Collection/Iterator/HashKeyTest.php +++ b/tests/Predis/Collection/Iterator/HashKeyTest.php @@ -483,7 +483,7 @@ class HashKeyTest extends PredisTestCase ->method('getCommandFactory') ->willReturn($this->getCommandFactory()); $client - ->expects($this->once(1)) + ->expects($this->once()) ->method('hscan') ->withConsecutive( ['key:hash', 0, ['MATCH' => 'field:*', 'COUNT' => 2]] diff --git a/tests/Predis/Command/Redis/EVALSHA_Test.php b/tests/Predis/Command/Redis/EVALSHA_Test.php index 76d6c984..2978cab0 100644 --- a/tests/Predis/Command/Redis/EVALSHA_Test.php +++ b/tests/Predis/Command/Redis/EVALSHA_Test.php @@ -61,7 +61,7 @@ class EVALSHA_Test extends PredisCommandTestCase */ public function testGetScriptHash(): void { - $command = $this->getCommandWithArgumentsArray([$sha1 = sha1('return true')], 0); + $command = $this->getCommandWithArgumentsArray([$sha1 = sha1('return true')]); $this->assertSame($sha1, $command->getScriptHash()); } diff --git a/tests/Predis/Connection/FactoryTest.php b/tests/Predis/Connection/FactoryTest.php index 8e1f2950..32620456 100644 --- a/tests/Predis/Connection/FactoryTest.php +++ b/tests/Predis/Connection/FactoryTest.php @@ -331,7 +331,7 @@ class FactoryTest extends PredisTestCase $connection->expects($this->once()) ->method('getParameters') ->will($this->returnValue($parameters)); - $connection->expects($this->once(1)) + $connection->expects($this->once()) ->method('addConnectCommand') ->with($this->isRedisCommand('AUTH', ['foobar'])); @@ -358,7 +358,7 @@ class FactoryTest extends PredisTestCase $connection->expects($this->once()) ->method('getParameters') ->will($this->returnValue($parameters)); - $connection->expects($this->once(1)) + $connection->expects($this->once()) ->method('addConnectCommand') ->with($this->isRedisCommand('AUTH', ['myusername', 'foobar'])); diff --git a/tests/Predis/Protocol/Text/ProtocolProcessorTest.php b/tests/Predis/Protocol/Text/ProtocolProcessorTest.php index 5509a8fc..4f4f8d45 100644 --- a/tests/Predis/Protocol/Text/ProtocolProcessorTest.php +++ b/tests/Predis/Protocol/Text/ProtocolProcessorTest.php @@ -82,7 +82,7 @@ class ProtocolProcessorTest extends PredisTestCase $connection = $this->getMockConnectionOfType('Predis\Connection\CompositeConnectionInterface'); $connection - ->expects($this->once(4)) + ->expects($this->once()) ->method('readLine') ->willReturn('*1');