From 8a4b3255676b57c7d0116a47ca7b7a7374f5c10b Mon Sep 17 00:00:00 2001 From: Rudolph Gottesheim Date: Wed, 13 May 2026 11:28:08 +0200 Subject: [PATCH 1/7] Add invalid fixtures for many rules with per-tool skip list Adds the snake-case test fixtures that were already covered as PascalCase files plus many new ones, and wires up RulesTest::SKIPPED_INVALID so each fixture can be skipped per tool when one of the two formatters has no equivalent rule. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/RulesTest.php | 33 +++++++++++++++++++ .../invalid/array-bracket-spacing.php | 6 ++++ tests/fixtures/invalid/array-not-trimmed.php | 5 +++ .../invalid/assignment-in-condition.php | 8 +++++ .../invalid/blank-line-after-phpdoc.php | 11 +++++++ .../fixtures/invalid/bracketed-namespace.php | 9 +++++ tests/fixtures/invalid/catch-exception.php | 13 ++++++++ tests/fixtures/invalid/control-signature.php | 7 ++++ tests/fixtures/invalid/dead-catch.php | 16 +++++++++ .../fixtures/invalid/deprecated-function.php | 7 ++++ tests/fixtures/invalid/else-if.php | 12 +++++++ tests/fixtures/invalid/empty-comment.php | 10 ++++++ tests/fixtures/invalid/empty-phpdoc.php | 9 +++++ tests/fixtures/invalid/extra-blank-lines.php | 11 +++++++ .../invalid/forbidden-author-annotation.php | 10 ++++++ .../invalid/forbidden-class-comment.php | 12 +++++++ .../invalid/forbidden-function-sizeof.php | 7 ++++ tests/fixtures/invalid/group-use.php | 7 ++++ tests/fixtures/invalid/inline-doc-comment.php | 7 ++++ .../fixtures/invalid/logical-operator-and.php | 5 +++ .../invalid/logical-operator-spacing.php | 5 +++ tests/fixtures/invalid/long-array-syntax.php | 5 +++ tests/fixtures/invalid/long-cast.php | 5 +++ tests/fixtures/invalid/long-type-hint.php | 11 +++++++ .../invalid/missing-const-visibility.php | 10 ++++++ .../invalid/missing-declare-strict-types.php | 3 ++ .../invalid/missing-space-after-construct.php | 12 +++++++ .../invalid/multiline-double-arrow.php | 8 +++++ .../fixtures/invalid/multiple-namespaces.php | 15 +++++++++ .../invalid/multiple-uses-per-line.php | 7 ++++ .../invalid/new-without-parentheses.php | 7 ++++ tests/fixtures/invalid/no-early-exit.php | 12 +++++++ .../invalid/no-space-around-equals.php | 5 +++ .../invalid/non-static-data-provider.php | 26 +++++++++++++++ .../nullable-type-for-null-default.php | 8 +++++ .../invalid/parameter-type-hint-spacing.php | 8 +++++ tests/fixtures/invalid/php4-constructor.php | 12 +++++++ tests/fixtures/invalid/phpdoc-not-trimmed.php | 12 +++++++ .../fixtures/invalid/property-declaration.php | 10 ++++++ .../invalid/return-type-hint-spacing.php | 8 +++++ .../invalid/self-member-reference.php | 18 ++++++++++ .../fixtures/invalid/snake-case-variable.php | 6 ++++ .../invalid/space-around-object-operator.php | 8 +++++ .../invalid/space-before-semicolon.php | 5 +++ tests/fixtures/invalid/superfluous-elseif.php | 13 ++++++++ .../fixtures/invalid/text-before-open-tag.php | 6 ++++ tests/fixtures/invalid/this-in-static.php | 13 ++++++++ .../invalid/trailing-comma-singleline.php | 5 +++ .../fixtures/invalid/trailing-whitespace.php | 5 +++ .../invalid/union-type-with-spaces.php | 8 +++++ .../invalid/unnecessary-final-modifier.php | 12 +++++++ tests/fixtures/invalid/unsorted-uses.php | 11 +++++++ tests/fixtures/invalid/unused-closure-use.php | 9 +++++ tests/fixtures/invalid/unused-use.php | 9 +++++ .../invalid/uppercase-php-function.php | 7 ++++ .../fixtures/invalid/uppercase-type-hint.php | 8 +++++ .../invalid/use-from-same-namespace.php | 9 +++++ .../invalid/use-leading-backslash.php | 9 +++++ tests/fixtures/invalid/useless-else.php | 12 +++++++ .../invalid/useless-if-with-return.php | 11 +++++++ .../fixtures/invalid/useless-parentheses.php | 8 +++++ .../invalid/whitespace-after-comma.php | 5 +++ tests/fixtures/invalid/yoda-comparison.php | 8 +++++ 63 files changed, 599 insertions(+) create mode 100644 tests/fixtures/invalid/array-bracket-spacing.php create mode 100644 tests/fixtures/invalid/array-not-trimmed.php create mode 100644 tests/fixtures/invalid/assignment-in-condition.php create mode 100644 tests/fixtures/invalid/blank-line-after-phpdoc.php create mode 100644 tests/fixtures/invalid/bracketed-namespace.php create mode 100644 tests/fixtures/invalid/catch-exception.php create mode 100644 tests/fixtures/invalid/control-signature.php create mode 100644 tests/fixtures/invalid/dead-catch.php create mode 100644 tests/fixtures/invalid/deprecated-function.php create mode 100644 tests/fixtures/invalid/else-if.php create mode 100644 tests/fixtures/invalid/empty-comment.php create mode 100644 tests/fixtures/invalid/empty-phpdoc.php create mode 100644 tests/fixtures/invalid/extra-blank-lines.php create mode 100644 tests/fixtures/invalid/forbidden-author-annotation.php create mode 100644 tests/fixtures/invalid/forbidden-class-comment.php create mode 100644 tests/fixtures/invalid/forbidden-function-sizeof.php create mode 100644 tests/fixtures/invalid/group-use.php create mode 100644 tests/fixtures/invalid/inline-doc-comment.php create mode 100644 tests/fixtures/invalid/logical-operator-and.php create mode 100644 tests/fixtures/invalid/logical-operator-spacing.php create mode 100644 tests/fixtures/invalid/long-array-syntax.php create mode 100644 tests/fixtures/invalid/long-cast.php create mode 100644 tests/fixtures/invalid/long-type-hint.php create mode 100644 tests/fixtures/invalid/missing-const-visibility.php create mode 100644 tests/fixtures/invalid/missing-declare-strict-types.php create mode 100644 tests/fixtures/invalid/missing-space-after-construct.php create mode 100644 tests/fixtures/invalid/multiline-double-arrow.php create mode 100644 tests/fixtures/invalid/multiple-namespaces.php create mode 100644 tests/fixtures/invalid/multiple-uses-per-line.php create mode 100644 tests/fixtures/invalid/new-without-parentheses.php create mode 100644 tests/fixtures/invalid/no-early-exit.php create mode 100644 tests/fixtures/invalid/no-space-around-equals.php create mode 100644 tests/fixtures/invalid/non-static-data-provider.php create mode 100644 tests/fixtures/invalid/nullable-type-for-null-default.php create mode 100644 tests/fixtures/invalid/parameter-type-hint-spacing.php create mode 100644 tests/fixtures/invalid/php4-constructor.php create mode 100644 tests/fixtures/invalid/phpdoc-not-trimmed.php create mode 100644 tests/fixtures/invalid/property-declaration.php create mode 100644 tests/fixtures/invalid/return-type-hint-spacing.php create mode 100644 tests/fixtures/invalid/self-member-reference.php create mode 100644 tests/fixtures/invalid/snake-case-variable.php create mode 100644 tests/fixtures/invalid/space-around-object-operator.php create mode 100644 tests/fixtures/invalid/space-before-semicolon.php create mode 100644 tests/fixtures/invalid/superfluous-elseif.php create mode 100644 tests/fixtures/invalid/text-before-open-tag.php create mode 100644 tests/fixtures/invalid/this-in-static.php create mode 100644 tests/fixtures/invalid/trailing-comma-singleline.php create mode 100644 tests/fixtures/invalid/trailing-whitespace.php create mode 100644 tests/fixtures/invalid/union-type-with-spaces.php create mode 100644 tests/fixtures/invalid/unnecessary-final-modifier.php create mode 100644 tests/fixtures/invalid/unsorted-uses.php create mode 100644 tests/fixtures/invalid/unused-closure-use.php create mode 100644 tests/fixtures/invalid/unused-use.php create mode 100644 tests/fixtures/invalid/uppercase-php-function.php create mode 100644 tests/fixtures/invalid/uppercase-type-hint.php create mode 100644 tests/fixtures/invalid/use-from-same-namespace.php create mode 100644 tests/fixtures/invalid/use-leading-backslash.php create mode 100644 tests/fixtures/invalid/useless-else.php create mode 100644 tests/fixtures/invalid/useless-if-with-return.php create mode 100644 tests/fixtures/invalid/useless-parentheses.php create mode 100644 tests/fixtures/invalid/whitespace-after-comma.php create mode 100644 tests/fixtures/invalid/yoda-comparison.php diff --git a/tests/RulesTest.php b/tests/RulesTest.php index a79c3c1..ceb411a 100644 --- a/tests/RulesTest.php +++ b/tests/RulesTest.php @@ -32,6 +32,39 @@ final class RulesTest extends TestCase ['HeredocNotIndented.php', 'phpcs'], // PHP CS Fixer has no rule for multiple classes per file ['multiple-classes-per-file.php', 'php-cs-fixer'], + // PHP CS Fixer has no equivalent sniff + ['space-before-semicolon.php', 'php-cs-fixer'], + ['array-bracket-spacing.php', 'php-cs-fixer'], + ['long-type-hint.php', 'php-cs-fixer'], + ['bracketed-namespace.php', 'php-cs-fixer'], + ['uppercase-type-hint.php', 'php-cs-fixer'], + ['forbidden-function-sizeof.php', 'php-cs-fixer'], + ['deprecated-function.php', 'php-cs-fixer'], + ['unnecessary-final-modifier.php', 'php-cs-fixer'], + ['php4-constructor.php', 'php-cs-fixer'], + ['text-before-open-tag.php', 'php-cs-fixer'], + ['this-in-static.php', 'php-cs-fixer'], + ['catch-exception.php', 'php-cs-fixer'], + ['assignment-in-condition.php', 'php-cs-fixer'], + ['dead-catch.php', 'php-cs-fixer'], + ['useless-if-with-return.php', 'php-cs-fixer'], + ['useless-parentheses.php', 'php-cs-fixer'], + ['unused-closure-use.php', 'php-cs-fixer'], + ['self-member-reference.php', 'php-cs-fixer'], + ['snake-case-variable.php', 'php-cs-fixer'], + ['uppercase-php-function.php', 'php-cs-fixer'], + ['forbidden-author-annotation.php', 'php-cs-fixer'], + ['forbidden-class-comment.php', 'php-cs-fixer'], + ['inline-doc-comment.php', 'php-cs-fixer'], + ['multiple-namespaces.php', 'php-cs-fixer'], + // PHPCS has no equivalent sniff + ['blank-line-after-phpdoc.php', 'phpcs'], + ['trailing-comma-singleline.php', 'phpcs'], + ['multiline-double-arrow.php', 'phpcs'], + ['phpdoc-not-trimmed.php', 'phpcs'], + ['array-not-trimmed.php', 'phpcs'], + ['whitespace-after-comma.php', 'phpcs'], + ['union-type-with-spaces.php', 'phpcs'], ]; private static function phpCsFixerCommand(string $file): string diff --git a/tests/fixtures/invalid/array-bracket-spacing.php b/tests/fixtures/invalid/array-bracket-spacing.php new file mode 100644 index 0000000..2afc667 --- /dev/null +++ b/tests/fixtures/invalid/array-bracket-spacing.php @@ -0,0 +1,6 @@ + 1]; +$bar = $foo[ 'a' ]; diff --git a/tests/fixtures/invalid/array-not-trimmed.php b/tests/fixtures/invalid/array-not-trimmed.php new file mode 100644 index 0000000..79efe5c --- /dev/null +++ b/tests/fixtures/invalid/array-not-trimmed.php @@ -0,0 +1,5 @@ +getMessage(); +} diff --git a/tests/fixtures/invalid/control-signature.php b/tests/fixtures/invalid/control-signature.php new file mode 100644 index 0000000..0f47c8e --- /dev/null +++ b/tests/fixtures/invalid/control-signature.php @@ -0,0 +1,7 @@ +getMessage(); +} catch (RuntimeException $e) { + echo $e->getMessage(); +} diff --git a/tests/fixtures/invalid/deprecated-function.php b/tests/fixtures/invalid/deprecated-function.php new file mode 100644 index 0000000..aebc1c9 --- /dev/null +++ b/tests/fixtures/invalid/deprecated-function.php @@ -0,0 +1,7 @@ + 1, +]; diff --git a/tests/fixtures/invalid/multiple-namespaces.php b/tests/fixtures/invalid/multiple-namespaces.php new file mode 100644 index 0000000..4627ce4 --- /dev/null +++ b/tests/fixtures/invalid/multiple-namespaces.php @@ -0,0 +1,15 @@ + 0) { + return $value * 2; + } else { + return 0; + } +} diff --git a/tests/fixtures/invalid/no-space-around-equals.php b/tests/fixtures/invalid/no-space-around-equals.php new file mode 100644 index 0000000..b6cc543 --- /dev/null +++ b/tests/fixtures/invalid/no-space-around-equals.php @@ -0,0 +1,5 @@ + + */ + public function provideValues(): iterable + { + yield [1]; + } +} diff --git a/tests/fixtures/invalid/nullable-type-for-null-default.php b/tests/fixtures/invalid/nullable-type-for-null-default.php new file mode 100644 index 0000000..dbcd1d1 --- /dev/null +++ b/tests/fixtures/invalid/nullable-type-for-null-default.php @@ -0,0 +1,8 @@ +bar = 1; diff --git a/tests/fixtures/invalid/space-before-semicolon.php b/tests/fixtures/invalid/space-before-semicolon.php new file mode 100644 index 0000000..7ed9502 --- /dev/null +++ b/tests/fixtures/invalid/space-before-semicolon.php @@ -0,0 +1,5 @@ + 0) { + return 1; + } elseif ($value < 0) { + return -1; + } + return 0; +} diff --git a/tests/fixtures/invalid/text-before-open-tag.php b/tests/fixtures/invalid/text-before-open-tag.php new file mode 100644 index 0000000..c79e54f --- /dev/null +++ b/tests/fixtures/invalid/text-before-open-tag.php @@ -0,0 +1,6 @@ +text +bar; + } +} diff --git a/tests/fixtures/invalid/trailing-comma-singleline.php b/tests/fixtures/invalid/trailing-comma-singleline.php new file mode 100644 index 0000000..731d94f --- /dev/null +++ b/tests/fixtures/invalid/trailing-comma-singleline.php @@ -0,0 +1,5 @@ + 0) { + return 1; + } else { + return 0; + } +} diff --git a/tests/fixtures/invalid/useless-if-with-return.php b/tests/fixtures/invalid/useless-if-with-return.php new file mode 100644 index 0000000..e4ba109 --- /dev/null +++ b/tests/fixtures/invalid/useless-if-with-return.php @@ -0,0 +1,11 @@ + 0) { + return true; + } + return false; +} diff --git a/tests/fixtures/invalid/useless-parentheses.php b/tests/fixtures/invalid/useless-parentheses.php new file mode 100644 index 0000000..71ba622 --- /dev/null +++ b/tests/fixtures/invalid/useless-parentheses.php @@ -0,0 +1,8 @@ + Date: Wed, 13 May 2026 11:32:17 +0200 Subject: [PATCH 2/7] Enable rules that were missing and drop matching skips Adds twelve previously-unconfigured PHP CS Fixer rules and three Slevomat sniffs that cover behavior we were already testing for via PHPCS or PHP CS Fixer respectively, removing 16 entries from RulesTest::SKIPPED_INVALID. self_accessor moves from the strict ruleset to the basic one because the test harness runs both tools against the basic config. Co-Authored-By: Claude Opus 4.7 (1M context) --- Eventjet/ruleset.xml | 14 ++++++++++++ php-cs-fixer-rules.php | 40 +++++++++++++++++++++++++++++++++++ php-cs-fixer-strict-rules.php | 1 - tests/RulesTest.php | 16 -------------- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/Eventjet/ruleset.xml b/Eventjet/ruleset.xml index d8607a3..5d729fc 100644 --- a/Eventjet/ruleset.xml +++ b/Eventjet/ruleset.xml @@ -299,4 +299,18 @@ + + + + + + + + + + + + + diff --git a/php-cs-fixer-rules.php b/php-cs-fixer-rules.php index 9bb9dc2..cf4a280 100644 --- a/php-cs-fixer-rules.php +++ b/php-cs-fixer-rules.php @@ -23,6 +23,20 @@ 'function_declaration' => [ 'closure_fn_spacing' => 'none', ], + 'general_phpdoc_annotation_remove' => [ + 'annotations' => [ + 'api', + 'author', + 'category', + 'copyright', + 'created', + 'license', + 'package', + 'since', + 'subpackage', + 'version', + ], + ], 'global_namespace_import' => [ 'import_classes' => true, 'import_constants' => true, @@ -31,19 +45,25 @@ 'heredoc_indentation' => [ 'indentation' => 'start_plus_one', ], + 'lambda_not_used_import' => true, 'native_constant_invocation' => [ 'scope' => 'namespaced', 'strict' => true, ], + 'native_function_casing' => true, 'native_function_invocation' => [ 'include' => ['@all'], 'scope' => 'namespaced', 'strict' => true, ], + 'native_type_declaration_casing' => true, 'new_with_parentheses' => [ 'named_class' => true, 'anonymous_class' => false, ], + 'no_alias_functions' => [ + 'sets' => ['@internal'], + ], 'no_blank_lines_after_phpdoc' => true, 'no_empty_comment' => true, 'no_empty_phpdoc' => true, @@ -59,12 +79,28 @@ ], ], 'no_multiline_whitespace_around_double_arrow' => true, + 'no_singleline_whitespace_before_semicolons' => true, 'no_superfluous_elseif' => true, 'no_superfluous_phpdoc_tags' => [ // Psalm wants us to have an explicit type annotation whenever we assign `mixed` to a variable. 'allow_mixed' => true, ], 'no_trailing_comma_in_singleline' => true, + 'no_unneeded_control_parentheses' => [ + 'statements' => [ + 'break', + 'clone', + 'continue', + 'echo_print', + 'negative_instanceof', + 'others', + 'return', + 'switch_case', + 'yield', + 'yield_from', + ], + ], + 'no_unneeded_final_method' => true, 'no_unused_imports' => true, 'no_useless_else' => true, 'no_useless_concat_operator' => true, @@ -73,8 +109,12 @@ 'imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha', ], + 'phpdoc_scalar' => true, 'phpdoc_trim' => true, + 'phpdoc_var_annotation_correct_order' => true, 'php_unit_data_provider_static' => true, + 'self_accessor' => true, + 'simplified_if_return' => true, 'single_quote' => true, 'single_space_around_construct' => true, 'strict_comparison' => true, diff --git a/php-cs-fixer-strict-rules.php b/php-cs-fixer-strict-rules.php index 8916b48..866fba9 100644 --- a/php-cs-fixer-strict-rules.php +++ b/php-cs-fixer-strict-rules.php @@ -39,7 +39,6 @@ 'sort_algorithm' => 'none', 'null_adjustment' => 'always_last', ], - 'self_accessor' => true, 'static_lambda' => true, 'trailing_comma_in_multiline' => [ 'elements' => [ diff --git a/tests/RulesTest.php b/tests/RulesTest.php index ceb411a..1575401 100644 --- a/tests/RulesTest.php +++ b/tests/RulesTest.php @@ -33,38 +33,22 @@ final class RulesTest extends TestCase // PHP CS Fixer has no rule for multiple classes per file ['multiple-classes-per-file.php', 'php-cs-fixer'], // PHP CS Fixer has no equivalent sniff - ['space-before-semicolon.php', 'php-cs-fixer'], ['array-bracket-spacing.php', 'php-cs-fixer'], - ['long-type-hint.php', 'php-cs-fixer'], ['bracketed-namespace.php', 'php-cs-fixer'], - ['uppercase-type-hint.php', 'php-cs-fixer'], - ['forbidden-function-sizeof.php', 'php-cs-fixer'], ['deprecated-function.php', 'php-cs-fixer'], - ['unnecessary-final-modifier.php', 'php-cs-fixer'], ['php4-constructor.php', 'php-cs-fixer'], ['text-before-open-tag.php', 'php-cs-fixer'], ['this-in-static.php', 'php-cs-fixer'], ['catch-exception.php', 'php-cs-fixer'], ['assignment-in-condition.php', 'php-cs-fixer'], ['dead-catch.php', 'php-cs-fixer'], - ['useless-if-with-return.php', 'php-cs-fixer'], - ['useless-parentheses.php', 'php-cs-fixer'], - ['unused-closure-use.php', 'php-cs-fixer'], - ['self-member-reference.php', 'php-cs-fixer'], ['snake-case-variable.php', 'php-cs-fixer'], - ['uppercase-php-function.php', 'php-cs-fixer'], - ['forbidden-author-annotation.php', 'php-cs-fixer'], ['forbidden-class-comment.php', 'php-cs-fixer'], - ['inline-doc-comment.php', 'php-cs-fixer'], ['multiple-namespaces.php', 'php-cs-fixer'], // PHPCS has no equivalent sniff ['blank-line-after-phpdoc.php', 'phpcs'], ['trailing-comma-singleline.php', 'phpcs'], ['multiline-double-arrow.php', 'phpcs'], - ['phpdoc-not-trimmed.php', 'phpcs'], - ['array-not-trimmed.php', 'phpcs'], - ['whitespace-after-comma.php', 'phpcs'], - ['union-type-with-spaces.php', 'phpcs'], ]; private static function phpCsFixerCommand(string $file): string From 8b5da0a03c7f6c3e2bcab2278539e2c9b120130d Mon Sep 17 00:00:00 2001 From: Rudolph Gottesheim Date: Wed, 13 May 2026 12:12:12 +0200 Subject: [PATCH 3/7] Enable no_spaces_around_offset and drop matching skip Co-Authored-By: Claude Opus 4.7 (1M context) --- php-cs-fixer-rules.php | 1 + tests/RulesTest.php | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/php-cs-fixer-rules.php b/php-cs-fixer-rules.php index cf4a280..5447b64 100644 --- a/php-cs-fixer-rules.php +++ b/php-cs-fixer-rules.php @@ -80,6 +80,7 @@ ], 'no_multiline_whitespace_around_double_arrow' => true, 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_around_offset' => true, 'no_superfluous_elseif' => true, 'no_superfluous_phpdoc_tags' => [ // Psalm wants us to have an explicit type annotation whenever we assign `mixed` to a variable. diff --git a/tests/RulesTest.php b/tests/RulesTest.php index 1575401..8f5a3a5 100644 --- a/tests/RulesTest.php +++ b/tests/RulesTest.php @@ -33,7 +33,6 @@ final class RulesTest extends TestCase // PHP CS Fixer has no rule for multiple classes per file ['multiple-classes-per-file.php', 'php-cs-fixer'], // PHP CS Fixer has no equivalent sniff - ['array-bracket-spacing.php', 'php-cs-fixer'], ['bracketed-namespace.php', 'php-cs-fixer'], ['deprecated-function.php', 'php-cs-fixer'], ['php4-constructor.php', 'php-cs-fixer'], From 14ed448de57e5b8bebaa9827d9cee78efca1f66b Mon Sep 17 00:00:00 2001 From: Rudolph Gottesheim Date: Wed, 13 May 2026 12:26:49 +0200 Subject: [PATCH 4/7] Enable no_php4_constructor and drop matching skip The fixer rule is a no-op on namespaced classes (PHP 4 constructors are meaningless there), so the fixture also has to drop its namespace. Co-Authored-By: Claude Opus 4.7 (1M context) --- php-cs-fixer-rules.php | 1 + tests/RulesTest.php | 1 - tests/fixtures/invalid/php4-constructor.php | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/php-cs-fixer-rules.php b/php-cs-fixer-rules.php index 5447b64..7d9b7e1 100644 --- a/php-cs-fixer-rules.php +++ b/php-cs-fixer-rules.php @@ -79,6 +79,7 @@ ], ], 'no_multiline_whitespace_around_double_arrow' => true, + 'no_php4_constructor' => true, 'no_singleline_whitespace_before_semicolons' => true, 'no_spaces_around_offset' => true, 'no_superfluous_elseif' => true, diff --git a/tests/RulesTest.php b/tests/RulesTest.php index 8f5a3a5..f804e8c 100644 --- a/tests/RulesTest.php +++ b/tests/RulesTest.php @@ -35,7 +35,6 @@ final class RulesTest extends TestCase // PHP CS Fixer has no equivalent sniff ['bracketed-namespace.php', 'php-cs-fixer'], ['deprecated-function.php', 'php-cs-fixer'], - ['php4-constructor.php', 'php-cs-fixer'], ['text-before-open-tag.php', 'php-cs-fixer'], ['this-in-static.php', 'php-cs-fixer'], ['catch-exception.php', 'php-cs-fixer'], diff --git a/tests/fixtures/invalid/php4-constructor.php b/tests/fixtures/invalid/php4-constructor.php index ffa42be..88be839 100644 --- a/tests/fixtures/invalid/php4-constructor.php +++ b/tests/fixtures/invalid/php4-constructor.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Invalid; - class Php4Constructor { public function Php4Constructor() From f16a613e43c7b54f7f2c33c044a9dba6208e7e40 Mon Sep 17 00:00:00 2001 From: Rudolph Gottesheim Date: Wed, 13 May 2026 16:41:37 +0200 Subject: [PATCH 5/7] Drop StaticThisUsage and InlineDocCommentDeclaration.InvalidFormat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHPStan and Psalm both flag `$this` in static methods and malformed inline `@var` annotations, so CS rules for the same patterns duplicate lint work. Disable them on both sides: - `Squiz.Scope.StaticThisUsage` set to severity 0 - `SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration` keeps its other codes (InvalidCommentType, MissingVariable, NoAssignment — genuine format/structure checks) but excludes InvalidFormat - `phpdoc_var_annotation_correct_order` set to false so the fixer doesn't silently canonicalize the same shape away Move both fixtures from invalid/ to valid/ and register them in EXPECTED_REL so the SA-overlap gate asserts both SAs keep flagging them. Rename this-in-static.php to ThisInStatic.php to satisfy Squiz.Classes.ClassFileName. Co-Authored-By: Claude Opus 4.7 (1M context) --- Eventjet/ruleset.xml | 18 ++++++++++++++---- php-cs-fixer-rules.php | 7 ++++++- tests/RulesTest.php | 1 - tests/check-sa-overlap.sh | 2 ++ tests/fixtures/invalid/inline-doc-comment.php | 7 ------- tests/fixtures/invalid/this-in-static.php | 13 ------------- tests/fixtures/valid/ThisInStatic.php | 19 +++++++++++++++++++ tests/fixtures/valid/inline-doc-comment.php | 15 +++++++++++++++ 8 files changed, 56 insertions(+), 26 deletions(-) delete mode 100644 tests/fixtures/invalid/inline-doc-comment.php delete mode 100644 tests/fixtures/invalid/this-in-static.php create mode 100644 tests/fixtures/valid/ThisInStatic.php create mode 100644 tests/fixtures/valid/inline-doc-comment.php diff --git a/Eventjet/ruleset.xml b/Eventjet/ruleset.xml index 122cea2..ca4b4aa 100644 --- a/Eventjet/ruleset.xml +++ b/Eventjet/ruleset.xml @@ -80,8 +80,12 @@ - - + + + 0 + @@ -148,8 +152,14 @@ - - + + + + diff --git a/php-cs-fixer-rules.php b/php-cs-fixer-rules.php index 61c740e..8ed1b35 100644 --- a/php-cs-fixer-rules.php +++ b/php-cs-fixer-rules.php @@ -113,7 +113,12 @@ ], 'phpdoc_scalar' => true, 'phpdoc_trim' => true, - 'phpdoc_var_annotation_correct_order' => true, + // Wrong-order inline `@var` is lint territory — PHPStan and Psalm both + // fail to bind the type. Auto-canonicalizing it on the CS side hides the + // mistake from SA feedback instead of letting the user see and fix it, + // so keep this rule explicitly off (paired with the InvalidFormat exclude + // in Eventjet/ruleset.xml). + 'phpdoc_var_annotation_correct_order' => false, 'php_unit_data_provider_static' => true, 'self_accessor' => true, 'simplified_if_return' => true, diff --git a/tests/RulesTest.php b/tests/RulesTest.php index f804e8c..245ec17 100644 --- a/tests/RulesTest.php +++ b/tests/RulesTest.php @@ -36,7 +36,6 @@ final class RulesTest extends TestCase ['bracketed-namespace.php', 'php-cs-fixer'], ['deprecated-function.php', 'php-cs-fixer'], ['text-before-open-tag.php', 'php-cs-fixer'], - ['this-in-static.php', 'php-cs-fixer'], ['catch-exception.php', 'php-cs-fixer'], ['assignment-in-condition.php', 'php-cs-fixer'], ['dead-catch.php', 'php-cs-fixer'], diff --git a/tests/check-sa-overlap.sh b/tests/check-sa-overlap.sh index dd31eb0..d2b3590 100755 --- a/tests/check-sa-overlap.sh +++ b/tests/check-sa-overlap.sh @@ -25,7 +25,9 @@ fi cd "$(dirname "$0")/.." EXPECTED_REL=( + tests/fixtures/valid/inline-doc-comment.php tests/fixtures/valid/loose-comparison.php + tests/fixtures/valid/ThisInStatic.php ) for f in "${EXPECTED_REL[@]}"; do diff --git a/tests/fixtures/invalid/inline-doc-comment.php b/tests/fixtures/invalid/inline-doc-comment.php deleted file mode 100644 index 1ba894d..0000000 --- a/tests/fixtures/invalid/inline-doc-comment.php +++ /dev/null @@ -1,7 +0,0 @@ -bar; - } -} diff --git a/tests/fixtures/valid/ThisInStatic.php b/tests/fixtures/valid/ThisInStatic.php new file mode 100644 index 0000000..691be33 --- /dev/null +++ b/tests/fixtures/valid/ThisInStatic.php @@ -0,0 +1,19 @@ +bar; + } +} diff --git a/tests/fixtures/valid/inline-doc-comment.php b/tests/fixtures/valid/inline-doc-comment.php new file mode 100644 index 0000000..2a5672a --- /dev/null +++ b/tests/fixtures/valid/inline-doc-comment.php @@ -0,0 +1,15 @@ + Date: Wed, 13 May 2026 16:53:07 +0200 Subject: [PATCH 6/7] Rewrite 8 fixtures so PHPStan and Psalm don't both flag them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These fixtures previously had constant or trivially-reducible operands (e.g. `if(true)`, `'bar' === 'bar'`, `true AND false`) which both PHPStan and Psalm flag — putting them in the PHPStan ∩ Psalm intersection that tests/check-sa-overlap.sh enforces as the "drop the CS rule" signal. The CS rules these fixtures exercise are NOT being dropped — only the fixture content is reshaped so the SAs lose the ability to fold the expression statically, while the CS-side violation (missing space, `else if`, `AND`, yoda, PHP4 constructor, unsorted uses, etc.) stays intact. - control-signature.php: `if(true)` → `if($cond)` from bool param - else-if.php: $foo from int param, no longer constant - logical-operator-and.php: `true AND false` → `$a AND $b` inside if() to also dodge "unused result of and" - logical-operator-spacing.php: `true&&false` → `$a&&$b` returned from a function - missing-space-after-construct.php: added `@return iterable` so the yielded value is no longer mixed - php4-constructor.php: added `: void` return type - unsorted-uses.php: dropped the unreachable second throw - yoda-comparison.php: $foo from string param, no longer constant Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/fixtures/invalid/control-signature.php | 7 +++++-- tests/fixtures/invalid/else-if.php | 16 +++++++++------- tests/fixtures/invalid/logical-operator-and.php | 7 ++++++- .../invalid/logical-operator-spacing.php | 5 ++++- .../invalid/missing-space-after-construct.php | 1 + tests/fixtures/invalid/php4-constructor.php | 2 +- tests/fixtures/invalid/unsorted-uses.php | 1 - tests/fixtures/invalid/yoda-comparison.php | 8 +++++--- 8 files changed, 31 insertions(+), 16 deletions(-) diff --git a/tests/fixtures/invalid/control-signature.php b/tests/fixtures/invalid/control-signature.php index 0f47c8e..153c4f2 100644 --- a/tests/fixtures/invalid/control-signature.php +++ b/tests/fixtures/invalid/control-signature.php @@ -2,6 +2,9 @@ declare(strict_types=1); -if(true) { - echo 'yes'; +function controlSignatureCheck(bool $cond): void +{ + if($cond) { + echo 'yes'; + } } diff --git a/tests/fixtures/invalid/else-if.php b/tests/fixtures/invalid/else-if.php index eb47dfd..ff6f5a9 100644 --- a/tests/fixtures/invalid/else-if.php +++ b/tests/fixtures/invalid/else-if.php @@ -2,11 +2,13 @@ declare(strict_types=1); -$foo = 1; -if ($foo === 1) { - echo 'one'; -} else if ($foo === 2) { - echo 'two'; -} else { - echo 'other'; +function elseIfCheck(int $foo): void +{ + if ($foo === 1) { + echo 'one'; + } else if ($foo === 2) { + echo 'two'; + } else { + echo 'other'; + } } diff --git a/tests/fixtures/invalid/logical-operator-and.php b/tests/fixtures/invalid/logical-operator-and.php index b87c724..cfab178 100644 --- a/tests/fixtures/invalid/logical-operator-and.php +++ b/tests/fixtures/invalid/logical-operator-and.php @@ -2,4 +2,9 @@ declare(strict_types=1); -$foo = true AND false; +function logicalOperatorAndCheck(bool $a, bool $b): void +{ + if ($a AND $b) { + echo 'yes'; + } +} diff --git a/tests/fixtures/invalid/logical-operator-spacing.php b/tests/fixtures/invalid/logical-operator-spacing.php index d51f6db..374f229 100644 --- a/tests/fixtures/invalid/logical-operator-spacing.php +++ b/tests/fixtures/invalid/logical-operator-spacing.php @@ -2,4 +2,7 @@ declare(strict_types=1); -$foo = true&&false; +function logicalOperatorSpacingCheck(bool $a, bool $b): bool +{ + return $a&&$b; +} diff --git a/tests/fixtures/invalid/missing-space-after-construct.php b/tests/fixtures/invalid/missing-space-after-construct.php index 34939c1..d854a17 100644 --- a/tests/fixtures/invalid/missing-space-after-construct.php +++ b/tests/fixtures/invalid/missing-space-after-construct.php @@ -2,6 +2,7 @@ declare(strict_types=1); +/** @return iterable */ function generator(): iterable { yield(1); diff --git a/tests/fixtures/invalid/php4-constructor.php b/tests/fixtures/invalid/php4-constructor.php index 88be839..e014458 100644 --- a/tests/fixtures/invalid/php4-constructor.php +++ b/tests/fixtures/invalid/php4-constructor.php @@ -4,7 +4,7 @@ class Php4Constructor { - public function Php4Constructor() + public function Php4Constructor(): void { } } diff --git a/tests/fixtures/invalid/unsorted-uses.php b/tests/fixtures/invalid/unsorted-uses.php index 9d54537..fdf507c 100644 --- a/tests/fixtures/invalid/unsorted-uses.php +++ b/tests/fixtures/invalid/unsorted-uses.php @@ -8,4 +8,3 @@ use LogicException; throw new LogicException('a'); -throw new RuntimeException('b'); diff --git a/tests/fixtures/invalid/yoda-comparison.php b/tests/fixtures/invalid/yoda-comparison.php index 425882a..5095c0c 100644 --- a/tests/fixtures/invalid/yoda-comparison.php +++ b/tests/fixtures/invalid/yoda-comparison.php @@ -2,7 +2,9 @@ declare(strict_types=1); -$foo = 'bar'; -if ('bar' === $foo) { - echo $foo; +function yodaComparisonCheck(string $foo): void +{ + if ('bar' === $foo) { + echo $foo; + } } From a90e136efce6d5df92cec09d79956b45542c08ff Mon Sep 17 00:00:00 2001 From: Rudolph Gottesheim Date: Mon, 18 May 2026 10:37:19 +0200 Subject: [PATCH 7/7] Raise minimum versions to fix PHP 8.3/8.4 prefer-lowest CI The --prefer-lowest CI job was failing on PHP 8.3 because: - slevomat/coding-standard 8.4 lacks the DNFTypeHintFormat sniff referenced in Eventjet/ruleset.xml. The sniff was added in 8.16. - friendsofphp/php-cs-fixer 3.32 caps supported PHP at 8.2 and trips the tokenizer on PHP 8.3+ even with PHP_CS_FIXER_IGNORE_ENV=1. 3.65 raises the cap to 8.3 and runs cleanly on 8.4 under the env override. Co-Authored-By: Claude Opus 4.7 (1M context) --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e57d3ec..7773f81 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,8 @@ "require": { "php": "^8.1", "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6 || ^0.7 || ^1.0", - "friendsofphp/php-cs-fixer": "^3.32", - "slevomat/coding-standard": "^8.4", + "friendsofphp/php-cs-fixer": "^3.65", + "slevomat/coding-standard": "^8.16", "squizlabs/php_codesniffer": "^3.6.1", "webimpress/coding-standard": "^1.1" },