From 2c91652a36da874c5ee17a92cd352fde5b44eb37 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Dec 2025 19:14:57 +0000 Subject: [PATCH] Fix PHPStan level 2 errors and remove @phpstan-ignore-line - Remove unused Processor::process() method with @phpstan-ignore-line - Fix DataApiObject: use self:: for private method, use ReflectionNamedType - Refactor ValueFormatter to use match statement instead of dynamic call - Fix Payment.php: explicit boolean check for array condition - Fix Utils.php: explicit boolean check in ternary operator - Upgrade PHPStan level from 1 to 2 in Makefile - Update phpstan.neon: remove ValueFormatter ignore, document remaining ignores Resolves #15 --- Makefile | 2 +- phpstan.neon | 12 +++++------- src/DataApi/DataApiObject.php | 5 +++-- src/DataApi/Processors/Processor.php | 7 ------- src/DataApi/ValueFormatter.php | 26 ++++++++++++-------------- src/Payment.php | 2 +- src/Utils.php | 2 +- 7 files changed, 23 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index cda4fe0..5e4df1d 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ csf: vendor/bin/phpcbf --standard=ruleset.xml --extensions=php,phpt --tab-width=4 --ignore=temp -sp src tests phpstan: - vendor/bin/phpstan analyse -l 1 -c phpstan.neon --memory-limit=512M src + vendor/bin/phpstan analyse -l 2 -c phpstan.neon --memory-limit=512M src tests: vendor/bin/tester -s -p php --colors 1 -C tests diff --git a/phpstan.neon b/phpstan.neon index 4fc3dfb..67dfdea 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,17 +1,15 @@ parameters: ignoreErrors: - - # object to array + - # DataApiObject uses dynamic property access for toArray() serialization + # This is a core PHP pattern for DTOs that serialize via reflection message: '~^Variable property access on \$this\(Tp\\DataApi\\DataApiObject\)\.$~' path: %currentWorkingDirectory%/src/DataApi/DataApiObject.php - - # offsetGet, offsetSet + - # ArrayAccess implementation requires dynamic method dispatch to getters/setters message: '~^Variable method call on \$this\(Tp\\DataApi\\DataApiObject\)\.$~' path: %currentWorkingDirectory%/src/DataApi/DataApiObject.php - - # setProperty, getProperty + - # ReturnedPayment hydrates from request args using config-driven property names message: '~^Variable property access on \$this\(Tp\\ReturnedPayment\)\.$~' path: %currentWorkingDirectory%/src/ReturnedPayment.php - - # generic formaters - message: '~^Variable static method call on Tp\\DataApi\\ValueFormatter\.$~' - path: %currentWorkingDirectory%/src/DataApi/ValueFormatter.php - - # remote API call + - # SoapClient requires dynamic method dispatch for SOAP operations message: '~^Variable method call on SoapClient\.$~' path: %currentWorkingDirectory%/src/Helper/DataApi.php diff --git a/src/DataApi/DataApiObject.php b/src/DataApi/DataApiObject.php index 1069746..25b7836 100644 --- a/src/DataApi/DataApiObject.php +++ b/src/DataApi/DataApiObject.php @@ -5,6 +5,7 @@ use ArrayAccess; use ReflectionClass; use ReflectionMethod; +use ReflectionNamedType; use ReflectionProperty; use ReturnTypeWillChange; use Tp\Utils; @@ -49,7 +50,7 @@ static function (ReflectionProperty $property): bool { return self::filterDataProperties($property); } ); - $sortedDataProperties = static::sortDataProperties($dataProperties); + $sortedDataProperties = self::sortDataProperties($dataProperties); $propertyNames = []; foreach ($sortedDataProperties as $property) { @@ -149,7 +150,7 @@ public function offsetSet($offset, $value): void $reflectionMethod = new ReflectionMethod($this, $setterName); $parameterType = $reflectionMethod->getParameters()[0]->getType(); - assert($parameterType !== null); + assert($parameterType instanceof ReflectionNamedType); switch ($parameterType->getName()) { case 'int': diff --git a/src/DataApi/Processors/Processor.php b/src/DataApi/Processors/Processor.php index 41fb02a..b9d6071 100644 --- a/src/DataApi/Processors/Processor.php +++ b/src/DataApi/Processors/Processor.php @@ -7,13 +7,6 @@ abstract class Processor { - public static function process(array $input): array - { - $instance = new static(); /* @phpstan-ignore-line */ - // Start with an empty path []. - return $instance->processHash($input, []); - } - /** * @param string[]|int[] $currentPath */ diff --git a/src/DataApi/ValueFormatter.php b/src/DataApi/ValueFormatter.php index 94a3a82..172d6b6 100644 --- a/src/DataApi/ValueFormatter.php +++ b/src/DataApi/ValueFormatter.php @@ -18,25 +18,23 @@ class ValueFormatter public static function format(string $type, $value) { if (substr($type, -2) === '[]') { - return static::formatList(substr($type, 0, -2), $value); + return self::formatList(substr($type, 0, -2), $value); } - $isNull = $value === null; - if ($isNull) { + if ($value === null) { return null; } - $method = 'format' . ucfirst($type); - if (method_exists(self::class, $method)) { - return static::$method($value); - } - - if (class_exists($type) && $value instanceof $type) { - return $value; - } - - $message = 'Unknown type ' . $type . '.'; - throw new InvalidArgumentException($message); + return match ($type) { + 'int' => self::formatInt($value), + 'float' => self::formatFloat($value), + 'bool' => self::formatBool($value), + 'string' => self::formatString($value), + 'dateTime' => self::formatDateTime($value), + default => class_exists($type) && $value instanceof $type + ? $value + : throw new InvalidArgumentException('Unknown type ' . $type . '.'), + }; } public static function formatInt(?int $value): ?int diff --git a/src/Payment.php b/src/Payment.php index c405ca0..bd89d7d 100644 --- a/src/Payment.php +++ b/src/Payment.php @@ -358,7 +358,7 @@ public function getArgs(): array 'email' => $customerData->getEmail(), ]); - if ($customerDataArr) { + if ($customerDataArr !== []) { $input['customerData'] = Escaper::jsonEncode($customerDataArr); } } diff --git a/src/Utils.php b/src/Utils.php index 14b24c7..6fe6b9f 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -50,7 +50,7 @@ public static function isList(array $array): bool { $count = count($array); - $range = $count + $range = $count > 0 ? range(0, $count - 1) : [];