Increase phpstan level from 7 to 8

- Fixed all phpstan errors and ignoreds.
 - False positives now have a "Why:" comment on phpstan config.
This commit is contained in:
Alexandre Gomes Gaigalas 2023-02-18 13:38:47 -03:00
parent 8cafa3f298
commit 727e7ccbfa
19 changed files with 70 additions and 31 deletions

View file

@ -80,8 +80,12 @@ class NestedValidationException extends ValidationException implements IteratorA
return $this; return $this;
} }
/**
* @return SplObjectStorage<ValidationException, int>
*/
public function getIterator(): SplObjectStorage public function getIterator(): SplObjectStorage
{ {
/** @var SplObjectStorage<ValidationException, int> */
$childrenExceptions = new SplObjectStorage(); $childrenExceptions = new SplObjectStorage();
$recursiveIteratorIterator = $this->getRecursiveIterator(); $recursiveIteratorIterator = $this->getRecursiveIterator();
@ -182,6 +186,9 @@ class NestedValidationException extends ValidationException implements IteratorA
return implode(PHP_EOL, $messages); return implode(PHP_EOL, $messages);
} }
/**
* @return RecursiveIteratorIterator<RecursiveExceptionIterator>
*/
private function getRecursiveIterator(): RecursiveIteratorIterator private function getRecursiveIterator(): RecursiveIteratorIterator
{ {
return new RecursiveIteratorIterator( return new RecursiveIteratorIterator(

View file

@ -16,6 +16,8 @@ use UnexpectedValueException;
/** /**
* @author Henrique Moody <henriquemoody@gmail.com> * @author Henrique Moody <henriquemoody@gmail.com>
*
* @implements RecursiveIterator<int, ValidationException>
*/ */
final class RecursiveExceptionIterator implements RecursiveIterator, Countable final class RecursiveExceptionIterator implements RecursiveIterator, Countable
{ {

View file

@ -192,6 +192,8 @@ final class Factory
* *
* @throws InvalidClassException * @throws InvalidClassException
* @throws ReflectionException * @throws ReflectionException
*
* @return ReflectionClass<ValidationException|Validatable|object>
*/ */
private function createReflectionClass(string $name, string $parentName): ReflectionClass private function createReflectionClass(string $name, string $parentName): ReflectionClass
{ {
@ -237,6 +239,7 @@ final class Factory
} }
/** /**
* @param ReflectionObject|ReflectionClass<Validatable> $reflection
* @return mixed[] * @return mixed[]
*/ */
private function extractPropertiesValues(Validatable $validatable, ReflectionClass $reflection): array private function extractPropertiesValues(Validatable $validatable, ReflectionClass $reflection): array

View file

@ -65,6 +65,6 @@ trait CanValidateDateTime
return checkdate((int) $info['month'], $info['day'], (int) $info['year']); return checkdate((int) $info['month'], $info['day'], (int) $info['year']);
} }
return checkdate($info['month'] ?: 1, $info['day'] ?: 1, $info['year'] ?: 1); return checkdate($info['month'] ?: 1, 1, $info['year'] ?: 1);
} }
} }

View file

@ -11,6 +11,7 @@ namespace Respect\Validation\Rules;
use function ctype_digit; use function ctype_digit;
use function intval; use function intval;
use function is_scalar;
use function mb_strlen; use function mb_strlen;
use function strval; use function strval;
@ -30,6 +31,12 @@ final class Bsn extends AbstractRule
*/ */
public function validate($input): bool public function validate($input): bool
{ {
if (!is_scalar($input)) {
return false;
}
$input = (string) $input;
if (!ctype_digit($input)) { if (!ctype_digit($input)) {
return false; return false;
} }
@ -38,9 +45,9 @@ final class Bsn extends AbstractRule
return false; return false;
} }
$sum = -1 * intval($input[8]); /** @phpstan-ignore-line */ $sum = -1 * intval($input[8]);
for ($i = 9; $i > 1; --$i) { for ($i = 9; $i > 1; --$i) {
$sum += $i * intval($input[9 - $i]); /** @phpstan-ignore-line */ $sum += $i * intval($input[9 - $i]);
} }
return $sum !== 0 && $sum % 11 === 0; return $sum !== 0 && $sum % 11 === 0;

View file

@ -36,7 +36,7 @@ final class Date extends AbstractRule
/** /**
* @var string * @var string
*/ */
private $sample; /** @phpstan-ignore-line */ private $sample;
/** /**
* Initializes the rule. * Initializes the rule.

View file

@ -33,7 +33,7 @@ final class DateTime extends AbstractRule
/** /**
* @var string * @var string
*/ */
private $sample; /** @phpstan-ignore-line */ private $sample;
/** /**
* Initializes the rule. * Initializes the rule.

View file

@ -66,6 +66,6 @@ final class Decimal extends AbstractRule
return $formatted; return $formatted;
} }
return preg_replace('/^(\d+\.\d)0*$/', '$1', $formatted); return preg_replace('/^(\d+\.\d)0*$/', '$1', $formatted) ?: '';
} }
} }

View file

@ -41,7 +41,7 @@ final class Ip extends AbstractRule
/** /**
* @var string|null * @var string|null
*/ */
private $range; /** @phpstan-ignore-line */ private $range;
/** /**
* @var int|null * @var int|null

View file

@ -89,6 +89,7 @@ final class KeyNested extends AbstractRelated
} }
/** /**
* @param ArrayAccess<mixed, mixed> $array
* @param mixed $key * @param mixed $key
* *
* @return mixed * @return mixed

View file

@ -29,7 +29,7 @@ final class KeySet extends AbstractWrapper
/** /**
* @var mixed[] * @var mixed[]
*/ */
private $keys; /** @phpstan-ignore-line */ private $keys;
/** /**
* @var Key[] * @var Key[]

View file

@ -9,6 +9,7 @@ declare(strict_types=1);
namespace Respect\Validation\Rules; namespace Respect\Validation\Rules;
use function is_scalar;
use function ord; use function ord;
use function preg_match; use function preg_match;
@ -31,6 +32,12 @@ final class PolishIdCard extends AbstractRule
*/ */
public function validate($input): bool public function validate($input): bool
{ {
if (!is_scalar($input)) {
return false;
}
$input = (string) $input;
if (!preg_match('/^[A-Z0-9]{9}$/', $input)) { if (!preg_match('/^[A-Z0-9]{9}$/', $input)) {
return false; return false;
} }

View file

@ -33,7 +33,7 @@ final class Size extends AbstractRule
/** /**
* @var string|int|null * @var string|int|null
*/ */
private $minSize; /** @phpstan-ignore-line */ private $minSize;
/** /**
* @var float|null * @var float|null
@ -43,7 +43,7 @@ final class Size extends AbstractRule
/** /**
* @var string|int|null * @var string|int|null
*/ */
private $maxSize; /** @phpstan-ignore-line */ private $maxSize;
/** /**
* @var float|null * @var float|null
@ -57,9 +57,9 @@ final class Size extends AbstractRule
public function __construct($minSize = null, $maxSize = null) public function __construct($minSize = null, $maxSize = null)
{ {
$this->minSize = $minSize; $this->minSize = $minSize;
$this->minValue = $minSize ? $this->toBytes($minSize) : null; $this->minValue = $minSize ? $this->toBytes((string) $minSize) : null;
$this->maxSize = $maxSize; $this->maxSize = $maxSize;
$this->maxValue = $maxSize ? $this->toBytes($maxSize) : null; $this->maxValue = $maxSize ? $this->toBytes((string) $maxSize) : null;
} }
/** /**
@ -68,19 +68,19 @@ final class Size extends AbstractRule
public function validate($input): bool public function validate($input): bool
{ {
if ($input instanceof SplFileInfo) { if ($input instanceof SplFileInfo) {
return $this->isValidSize($input->getSize()); return $this->isValidSize((float) $input->getSize());
} }
if ($input instanceof UploadedFileInterface) { if ($input instanceof UploadedFileInterface) {
return $this->isValidSize($input->getSize()); return $this->isValidSize((float) $input->getSize());
} }
if ($input instanceof StreamInterface) { if ($input instanceof StreamInterface) {
return $this->isValidSize($input->getSize()); return $this->isValidSize((float) $input->getSize());
} }
if (is_string($input)) { if (is_string($input)) {
return $this->isValidSize((int) filesize($input)); return $this->isValidSize((float) filesize($input));
} }
return false; return false;
@ -89,14 +89,13 @@ final class Size extends AbstractRule
/** /**
* @todo Move it to a trait * @todo Move it to a trait
* *
* @param mixed $size
*/ */
private function toBytes($size): float private function toBytes(string $size): float
{ {
$value = $size; $value = $size;
$units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb']; $units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb'];
foreach ($units as $exponent => $unit) { foreach ($units as $exponent => $unit) {
if (!preg_match('/^(\d+(.\d+)?)' . $unit . '$/i', (string) $size, $matches)) { if (!preg_match('/^(\d+(.\d+)?)' . $unit . '$/i', $size, $matches)) {
continue; continue;
} }
$value = floatval($matches[1]) * 1024 ** $exponent; $value = floatval($matches[1]) * 1024 ** $exponent;
@ -104,7 +103,7 @@ final class Size extends AbstractRule
} }
if (!is_numeric($value)) { if (!is_numeric($value)) {
throw new ComponentException(sprintf('"%s" is not a recognized file size.', (string) $size)); throw new ComponentException(sprintf('"%s" is not a recognized file size.', $size));
} }
return (float) $value; return (float) $value;

View file

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Respect\Validation\Rules; namespace Respect\Validation\Rules;
use function is_array; use function is_array;
use function is_string;
use function mb_stripos; use function mb_stripos;
use function mb_strpos; use function mb_strpos;
use function reset; use function reset;
@ -63,7 +64,11 @@ final class StartsWith extends AbstractRule
return reset($input) == $this->startValue; return reset($input) == $this->startValue;
} }
return mb_stripos($input, $this->startValue) === 0; if (is_string($input) && is_string($this->startValue)) {
return mb_stripos($input, $this->startValue) === 0;
}
return false;
} }
/** /**
@ -75,6 +80,10 @@ final class StartsWith extends AbstractRule
return reset($input) === $this->startValue; return reset($input) === $this->startValue;
} }
return mb_strpos($input, $this->startValue) === 0; if (is_string($input) && is_string($this->startValue)) {
return mb_strpos($input, $this->startValue) === 0;
}
return false;
} }
} }

View file

@ -27,7 +27,7 @@ final class SubdivisionCode extends AbstractSearcher
/** /**
* @var string * @var string
*/ */
private $countryName; /** @phpstan-ignore-line */ private $countryName;
/** /**
* @var string[] * @var string[]

View file

@ -35,7 +35,7 @@ final class Time extends AbstractRule
/** /**
* @var string * @var string
*/ */
private $sample; /** @phpstan-ignore-line */ private $sample;
/** /**
* Initializes the rule. * Initializes the rule.

View file

@ -2,30 +2,30 @@ includes:
- vendor/phpstan/phpstan-deprecation-rules/rules.neon - vendor/phpstan/phpstan-deprecation-rules/rules.neon
- vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon - vendor/phpstan/phpstan-phpunit/rules.neon
parameters: parameters:
fileExtensions: fileExtensions:
- php - php
- phpt - phpt
checkGenericClassInNonGenericObjectType: false
checkMissingIterableValueType: false
ignoreErrors: ignoreErrors:
- -
message: '/Ternary operator condition is always false\./' # Why: Properties are read dynamically during message construction
path: library/Helpers/CanValidateDateTime.php message: '/Property Respect\\Validation\\Rules\\[a-zA-Z0-9\\_]+::\$[a-zA-Z0-9\\_]+ is never read, only written\./'
- -
# Why: SimpleXMLElement is weird and doesn't implement anything ArrayAccess-like
message: '/Instanceof between mixed and SimpleXMLElement will always evaluate to false\./' message: '/Instanceof between mixed and SimpleXMLElement will always evaluate to false\./'
path: library/Rules/ArrayVal.php path: library/Rules/ArrayVal.php
- -
# Why: This error is intentional, so PHPunit can test an invalid __callStatic call
message: '/Call to an undefined static method Respect\\Validation\\Validator::iDoNotExistSoIShouldThrowException/' message: '/Call to an undefined static method Respect\\Validation\\Validator::iDoNotExistSoIShouldThrowException/'
path: tests/unit/ValidatorTest.php path: tests/unit/ValidatorTest.php
- -
# Why: StaticValidator is a stub interface that types __callStatic
message: '/Call to static method PHPUnit\\Framework\\Assert::assertSame\(\) with Respect\\Validation\\Validator and Respect\\Validation\\ChainedValidator will always evaluate to false./' message: '/Call to static method PHPUnit\\Framework\\Assert::assertSame\(\) with Respect\\Validation\\Validator and Respect\\Validation\\ChainedValidator will always evaluate to false./'
path: tests/unit/ValidatorTest.php path: tests/unit/ValidatorTest.php
level: 7 level: 8
paths: paths:
- library/ - library/
- tests/ - tests/

View file

@ -31,7 +31,7 @@ final class AttributeTest extends RuleTestCase
/** /**
* @var string * @var string
*/ */
private $bar = self::PROPERTY_VALUE; /** @phpstan-ignore-line */ private $bar = self::PROPERTY_VALUE;
/** /**
* {@inheritDoc} * {@inheritDoc}

View file

@ -93,8 +93,12 @@ final class EachTest extends RuleTestCase
$rule->check(range(1, 3)); $rule->check(range(1, 3));
} }
/**
* @return Traversable<int>
*/
private function createTraversableInput(int $firstValue, int $lastValue): Traversable private function createTraversableInput(int $firstValue, int $lastValue): Traversable
{ {
/** @var SplStack<int> */
$input = new SplStack(); $input = new SplStack();
foreach (range($firstValue, $lastValue) as $value) { foreach (range($firstValue, $lastValue) as $value) {
$input->push($value); $input->push($value);