From f557cfeb8aefef68ec6d579d5c4e20f8b5ca80aa Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 8 Jun 2026 23:12:29 +0100 Subject: [PATCH 1/2] bump to PHP 8.4 --- .github/workflows/code_analysis.yaml | 2 +- .github/workflows/downgraded_release.yaml | 2 +- composer-dependency-analyser.php | 2 +- composer.json | 4 ++-- src/Doctrine/DoctrineEntityDocumentAnalyser.php | 8 +------- src/Helper/NamingHelper.php | 8 +------- src/Matcher/ArrayStringAndFnMatcher.php | 8 +------- src/PHPUnit/TestClassDetector.php | 8 +------- src/Rules/SeeAnnotationToTestRule.php | 8 +------- src/Rules/StringFileAbsolutePathExistsRule.php | 8 +------- .../AlreadyRegisteredAutodiscoveryServiceRule.php | 8 +------- .../PreferAutowireAttributeOverConfigParamRule.php | 8 +------- src/Rules/Symfony/RequiredOnlyInAbstractRule.php | 8 +------- src/Symfony/NodeAnalyzer/SymfonyControllerAnalyzer.php | 8 +------- src/TypeAnalyzer/RectorAllowedAutoloadedTypeAnalyzer.php | 8 +------- 15 files changed, 16 insertions(+), 82 deletions(-) diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 5c8057e38..4cc5a10dc 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -48,7 +48,7 @@ jobs: # see https://github.com/shivammathur/setup-php - uses: shivammathur/setup-php@v2 with: - php-version: 8.3 + php-version: 8.4 coverage: none # composer install cache - https://github.com/ramsey/composer-install diff --git a/.github/workflows/downgraded_release.yaml b/.github/workflows/downgraded_release.yaml index 8017081a6..4e79b035d 100644 --- a/.github/workflows/downgraded_release.yaml +++ b/.github/workflows/downgraded_release.yaml @@ -20,7 +20,7 @@ jobs: - uses: "shivammathur/setup-php@v2" with: - php-version: 8.3 + php-version: 8.4 coverage: none # invoke patches diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index e5911ab5e..4457ac772 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -5,7 +5,7 @@ use ShipMonk\ComposerDependencyAnalyser\Config\Configuration; use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType; -return (new Configuration()) +return new Configuration() ->addPathToExclude(__DIR__ . '/tests/Rules/Rector/NoInstanceOfStaticReflectionRule/Fixture') ->addPathToExclude(__DIR__ . '/tests/Rules/Enum/RequireUniqueEnumConstantRule/Fixture') ->addPathToExclude(__DIR__ . '/tests/Rules/ForbiddenExtendOfNonAbstractClassRule/Fixture') diff --git a/composer.json b/composer.json index fc1496520..55b60e833 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "description": "Set of Symplify rules for PHPStan", "license": "MIT", "require": { - "php": ">=8.3", + "php": ">=8.4", "webmozart/assert": "^1.12 || ^2.0", "phpstan/phpstan": "^2.1.33", "nette/utils": "^4.1", @@ -22,7 +22,7 @@ "tomasvotruba/unused-public": "^2.1", "tomasvotruba/type-coverage": "^2.1", "shipmonk/composer-dependency-analyser": "^1.8", - "rector/jack": "^0.4.0" + "rector/jack": "^1.0" }, "autoload": { "psr-4": { diff --git a/src/Doctrine/DoctrineEntityDocumentAnalyser.php b/src/Doctrine/DoctrineEntityDocumentAnalyser.php index 82c686f65..b1e35bc97 100644 --- a/src/Doctrine/DoctrineEntityDocumentAnalyser.php +++ b/src/Doctrine/DoctrineEntityDocumentAnalyser.php @@ -21,12 +21,6 @@ public static function isEntityClass(ClassReflection $classReflection): bool return false; } - foreach (self::ENTITY_DOCBLOCK_MARKERS as $entityDocBlockMarkers) { - if (str_contains($resolvedPhpDocBlock->getPhpDocString(), $entityDocBlockMarkers)) { - return true; - } - } - - return false; + return array_any(self::ENTITY_DOCBLOCK_MARKERS, fn ($entityDocBlockMarkers): bool => str_contains($resolvedPhpDocBlock->getPhpDocString(), $entityDocBlockMarkers)); } } diff --git a/src/Helper/NamingHelper.php b/src/Helper/NamingHelper.php index 3157f080c..55a6a774d 100644 --- a/src/Helper/NamingHelper.php +++ b/src/Helper/NamingHelper.php @@ -34,12 +34,6 @@ public static function isName(Node $node, string $name): bool */ public static function isNames(Node $node, array $names): bool { - foreach ($names as $name) { - if (self::isName($node, $name)) { - return true; - } - } - - return false; + return array_any($names, fn (string $name): bool => self::isName($node, $name)); } } diff --git a/src/Matcher/ArrayStringAndFnMatcher.php b/src/Matcher/ArrayStringAndFnMatcher.php index 3fd3e8d64..982294e94 100644 --- a/src/Matcher/ArrayStringAndFnMatcher.php +++ b/src/Matcher/ArrayStringAndFnMatcher.php @@ -18,13 +18,7 @@ public function isMatchWithIsA(string $currentValue, array $matchingValues): boo return true; } - foreach ($matchingValues as $matchingValue) { - if (is_a($currentValue, $matchingValue, true)) { - return true; - } - } - - return false; + return array_any($matchingValues, fn ($matchingValue): bool => is_a($currentValue, $matchingValue, true)); } /** diff --git a/src/PHPUnit/TestClassDetector.php b/src/PHPUnit/TestClassDetector.php index cfe4315cb..9535faabd 100644 --- a/src/PHPUnit/TestClassDetector.php +++ b/src/PHPUnit/TestClassDetector.php @@ -19,12 +19,6 @@ final class TestClassDetector public static function isTestClass(Scope $scope): bool { - foreach (self::TEST_FILE_SUFFIXES as $testFileSuffix) { - if (str_ends_with($scope->getFile(), $testFileSuffix)) { - return true; - } - } - - return false; + return array_any(self::TEST_FILE_SUFFIXES, fn ($testFileSuffix): bool => str_ends_with($scope->getFile(), (string) $testFileSuffix)); } } diff --git a/src/Rules/SeeAnnotationToTestRule.php b/src/Rules/SeeAnnotationToTestRule.php index 414d2d4c6..ce3eaf8a6 100644 --- a/src/Rules/SeeAnnotationToTestRule.php +++ b/src/Rules/SeeAnnotationToTestRule.php @@ -91,13 +91,7 @@ private function shouldSkipClassReflection(ClassReflection $classReflection): bo return true; } - foreach ($this->requiredSeeTypes as $requiredSeeType) { - if ($classReflection->is($requiredSeeType)) { - return false; - } - } - - return true; + return array_all($this->requiredSeeTypes, fn (string $requiredSeeType): bool => ! $classReflection->is($requiredSeeType)); } /** diff --git a/src/Rules/StringFileAbsolutePathExistsRule.php b/src/Rules/StringFileAbsolutePathExistsRule.php index be0f5911d..1e9fd45f5 100644 --- a/src/Rules/StringFileAbsolutePathExistsRule.php +++ b/src/Rules/StringFileAbsolutePathExistsRule.php @@ -86,12 +86,6 @@ private function getAbsoluteFilePath(Scope $scope, string $stringValue): string private function isDesiredFileSuffix(string $stringValue): bool { - foreach (self::SUFFIXES_TO_CHECK as $suffixToCheck) { - if (str_ends_with($stringValue, $suffixToCheck)) { - return true; - } - } - - return false; + return array_any(self::SUFFIXES_TO_CHECK, fn ($suffixToCheck): bool => str_ends_with($stringValue, (string) $suffixToCheck)); } } diff --git a/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php b/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php index 884003ce4..549628e8e 100644 --- a/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php +++ b/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php @@ -145,12 +145,6 @@ private function isClassInExcludedPaths(string $serviceClass, array $excludedPat return false; } - foreach ($excludedPaths as $excludedPath) { - if (str_starts_with($serviceFilePath, $excludedPath)) { - return true; - } - } - - return false; + return array_any($excludedPaths, fn ($excludedPath): bool => str_starts_with($serviceFilePath, (string) $excludedPath)); } } diff --git a/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php b/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php index ba6577990..920e87066 100644 --- a/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php +++ b/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php @@ -105,13 +105,7 @@ public function processNode(Node $node, Scope $scope): array private function hasPossibleParameterInject(MethodCall $methodCall): bool { - foreach ($methodCall->getArgs() as $arg) { - if ($this->isParamFuncOrString($arg->value)) { - return true; - } - } - - return false; + return array_any($methodCall->getArgs(), fn ($arg): bool => $this->isParamFuncOrString($arg->value)); } private function isParamFuncOrString(Expr $expr): bool diff --git a/src/Rules/Symfony/RequiredOnlyInAbstractRule.php b/src/Rules/Symfony/RequiredOnlyInAbstractRule.php index 1fa7c04bd..80dbed79b 100644 --- a/src/Rules/Symfony/RequiredOnlyInAbstractRule.php +++ b/src/Rules/Symfony/RequiredOnlyInAbstractRule.php @@ -90,13 +90,7 @@ private function shouldSkipClass(Scope $scope): bool return true; } - foreach (self::SKIPPED_PARENT_TYPES as $skippedParentType) { - if ($classReflection->is($skippedParentType)) { - return true; - } - } - - return false; + return array_any(self::SKIPPED_PARENT_TYPES, fn (string $skippedParentType): bool => $classReflection->is($skippedParentType)); } private function hasCircularDocNote(Node $node): bool diff --git a/src/Symfony/NodeAnalyzer/SymfonyControllerAnalyzer.php b/src/Symfony/NodeAnalyzer/SymfonyControllerAnalyzer.php index 7f04e28bb..49640a017 100644 --- a/src/Symfony/NodeAnalyzer/SymfonyControllerAnalyzer.php +++ b/src/Symfony/NodeAnalyzer/SymfonyControllerAnalyzer.php @@ -28,13 +28,7 @@ public static function isControllerScope(Scope $scope): bool } $classReflection = $scope->getClassReflection(); - foreach (self::CONTROLLER_TYPES as $controllerType) { - if ($classReflection->is($controllerType)) { - return true; - } - } - - return false; + return array_any(self::CONTROLLER_TYPES, fn (string $controllerType): bool => $classReflection->is($controllerType)); } public static function isControllerActionMethod(ClassMethod $classMethod): bool diff --git a/src/TypeAnalyzer/RectorAllowedAutoloadedTypeAnalyzer.php b/src/TypeAnalyzer/RectorAllowedAutoloadedTypeAnalyzer.php index e6445c89d..058f1da9a 100644 --- a/src/TypeAnalyzer/RectorAllowedAutoloadedTypeAnalyzer.php +++ b/src/TypeAnalyzer/RectorAllowedAutoloadedTypeAnalyzer.php @@ -31,13 +31,7 @@ final class RectorAllowedAutoloadedTypeAnalyzer public static function isAllowedType(Type $type): bool { if ($type instanceof UnionType) { - foreach ($type->getTypes() as $unionedType) { - if (! self::isAllowedType($unionedType)) { - return false; - } - } - - return true; + return array_all($type->getTypes(), fn (Type $unionedType): bool => self::isAllowedType($unionedType)); } if ($type instanceof ConstantStringType) { From b55cf493015ffd435edcdedd0b08eefaefaa3907 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 8 Jun 2026 23:13:28 +0100 Subject: [PATCH 2/2] bump --- composer-dependency-analyser.php | 1 - composer.json | 16 ++++++++-------- src/Doctrine/DoctrineEntityDocumentAnalyser.php | 2 +- src/Matcher/ArrayStringAndFnMatcher.php | 2 +- src/PHPUnit/TestClassDetector.php | 2 +- src/Rules/StringFileAbsolutePathExistsRule.php | 2 +- ...AlreadyRegisteredAutodiscoveryServiceRule.php | 2 +- ...referAutowireAttributeOverConfigParamRule.php | 3 ++- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index 4457ac772..493806f2a 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -21,7 +21,6 @@ ->ignoreErrorsOnPackage('symfony/service-contracts', [ErrorType::SHADOW_DEPENDENCY]) ->ignoreErrorsOnPackage('symfony/http-kernel', [ErrorType::SHADOW_DEPENDENCY]) ->ignoreErrorsOnPackage('symfony/event-dispatcher', [ErrorType::SHADOW_DEPENDENCY]) - ->ignoreErrorsOnPackage('symfony/deprecation-contracts', [ErrorType::SHADOW_DEPENDENCY]) ->ignoreErrorsOnPackage('symfony/dependency-injection', [ErrorType::SHADOW_DEPENDENCY]) ->ignoreErrorsOnPackage('symfony/config', [ErrorType::SHADOW_DEPENDENCY]) diff --git a/composer.json b/composer.json index 55b60e833..1f1ef2994 100644 --- a/composer.json +++ b/composer.json @@ -5,22 +5,22 @@ "license": "MIT", "require": { "php": ">=8.4", - "webmozart/assert": "^1.12 || ^2.0", - "phpstan/phpstan": "^2.1.33", + "webmozart/assert": " ^2.0", + "phpstan/phpstan": "^2.2", "nette/utils": "^4.1", "phpstan/phpdoc-parser": "^2.3" }, "require-dev": { "nikic/php-parser": "^5.7", - "phpunit/phpunit": "^12.5", - "symfony/framework-bundle": "6.1.*", - "phpecs/phpecs": "^2.2", + "phpunit/phpunit": "^13.0", + "symfony/framework-bundle": "^6.2", + "symplify/easy-coding-standard": "^13.0", "tomasvotruba/class-leak": "^2.1", - "rector/rector": "^2.3.6", + "rector/rector": "^2.4", "phpstan/extension-installer": "^1.4", "symplify/phpstan-extensions": "^12.0", - "tomasvotruba/unused-public": "^2.1", - "tomasvotruba/type-coverage": "^2.1", + "tomasvotruba/unused-public": "^2.2", + "tomasvotruba/type-coverage": "^2.2", "shipmonk/composer-dependency-analyser": "^1.8", "rector/jack": "^1.0" }, diff --git a/src/Doctrine/DoctrineEntityDocumentAnalyser.php b/src/Doctrine/DoctrineEntityDocumentAnalyser.php index b1e35bc97..8c1332bba 100644 --- a/src/Doctrine/DoctrineEntityDocumentAnalyser.php +++ b/src/Doctrine/DoctrineEntityDocumentAnalyser.php @@ -21,6 +21,6 @@ public static function isEntityClass(ClassReflection $classReflection): bool return false; } - return array_any(self::ENTITY_DOCBLOCK_MARKERS, fn ($entityDocBlockMarkers): bool => str_contains($resolvedPhpDocBlock->getPhpDocString(), $entityDocBlockMarkers)); + return array_any(self::ENTITY_DOCBLOCK_MARKERS, fn (string $entityDocBlockMarker): bool => str_contains($resolvedPhpDocBlock->getPhpDocString(), $entityDocBlockMarker)); } } diff --git a/src/Matcher/ArrayStringAndFnMatcher.php b/src/Matcher/ArrayStringAndFnMatcher.php index 982294e94..9643bcadc 100644 --- a/src/Matcher/ArrayStringAndFnMatcher.php +++ b/src/Matcher/ArrayStringAndFnMatcher.php @@ -18,7 +18,7 @@ public function isMatchWithIsA(string $currentValue, array $matchingValues): boo return true; } - return array_any($matchingValues, fn ($matchingValue): bool => is_a($currentValue, $matchingValue, true)); + return array_any($matchingValues, fn (string $matchingValue): bool => is_a($currentValue, $matchingValue, true)); } /** diff --git a/src/PHPUnit/TestClassDetector.php b/src/PHPUnit/TestClassDetector.php index 9535faabd..db68a12b6 100644 --- a/src/PHPUnit/TestClassDetector.php +++ b/src/PHPUnit/TestClassDetector.php @@ -19,6 +19,6 @@ final class TestClassDetector public static function isTestClass(Scope $scope): bool { - return array_any(self::TEST_FILE_SUFFIXES, fn ($testFileSuffix): bool => str_ends_with($scope->getFile(), (string) $testFileSuffix)); + return array_any(self::TEST_FILE_SUFFIXES, fn (string $testFileSuffix): bool => str_ends_with($scope->getFile(), $testFileSuffix)); } } diff --git a/src/Rules/StringFileAbsolutePathExistsRule.php b/src/Rules/StringFileAbsolutePathExistsRule.php index 1e9fd45f5..1f9842b29 100644 --- a/src/Rules/StringFileAbsolutePathExistsRule.php +++ b/src/Rules/StringFileAbsolutePathExistsRule.php @@ -86,6 +86,6 @@ private function getAbsoluteFilePath(Scope $scope, string $stringValue): string private function isDesiredFileSuffix(string $stringValue): bool { - return array_any(self::SUFFIXES_TO_CHECK, fn ($suffixToCheck): bool => str_ends_with($stringValue, (string) $suffixToCheck)); + return array_any(self::SUFFIXES_TO_CHECK, fn (string $suffixToCheck): bool => str_ends_with($stringValue, $suffixToCheck)); } } diff --git a/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php b/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php index 549628e8e..6dd091037 100644 --- a/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php +++ b/src/Rules/Symfony/ConfigClosure/AlreadyRegisteredAutodiscoveryServiceRule.php @@ -145,6 +145,6 @@ private function isClassInExcludedPaths(string $serviceClass, array $excludedPat return false; } - return array_any($excludedPaths, fn ($excludedPath): bool => str_starts_with($serviceFilePath, (string) $excludedPath)); + return array_any($excludedPaths, fn (string $excludedPath): bool => str_starts_with($serviceFilePath, $excludedPath)); } } diff --git a/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php b/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php index 920e87066..87d4c202e 100644 --- a/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php +++ b/src/Rules/Symfony/ConfigClosure/PreferAutowireAttributeOverConfigParamRule.php @@ -5,6 +5,7 @@ namespace Symplify\PHPStanRules\Rules\Symfony\ConfigClosure; use PhpParser\Node; +use PhpParser\Node\Arg; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Closure; use PhpParser\Node\Expr\FuncCall; @@ -105,7 +106,7 @@ public function processNode(Node $node, Scope $scope): array private function hasPossibleParameterInject(MethodCall $methodCall): bool { - return array_any($methodCall->getArgs(), fn ($arg): bool => $this->isParamFuncOrString($arg->value)); + return array_any($methodCall->getArgs(), fn (Arg $arg): bool => $this->isParamFuncOrString($arg->value)); } private function isParamFuncOrString(Expr $expr): bool