Skip to content

DX: add env for easier finding which fixer break a PHP syntax#9356

Merged
keradus merged 2 commits intoPHP-CS-Fixer:masterfrom
6b7562617765726c6f73:dx-show-which-fixer-breaks-systax
Jan 18, 2026
Merged

DX: add env for easier finding which fixer break a PHP syntax#9356
keradus merged 2 commits intoPHP-CS-Fixer:masterfrom
6b7562617765726c6f73:dx-show-which-fixer-breaks-systax

Conversation

@kubawerlos
Copy link
Copy Markdown
Member

It happened to me many times before, most recently when debugging #9349. The new env variable could also be used to ask the bug reporter for more details.

For the code:

$ cat test.php 
<?php class Foo {
    #[Bar(static function () {})]
    public function __invoke() {}
}

trying to check it resulted in a regular way:

$ docker compose run php-8.5 php php-cs-fixer check test.php -vvv
PHP CS Fixer 3.92.6-DEV Exceptional Exception by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.5.2

Found 0 of 1 files that can be fixed in 0.002 seconds, 20.00 MB memory used

Files that were not fixed due to errors reported during fixing:
   1) /fixer/test.php

                                    
        [UnexpectedValueException]  
        Missing block "start".      
                                    

      PhpCsFixer\Tokenizer\Tokens->findOppositeBlockEdge()
        in /fixer/src/Tokenizer/Tokens.php at line 549
      PhpCsFixer\Tokenizer\Tokens->findBlockStart()
        in /fixer/src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php at line 470
      PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer->findCommentBlockStart()
        in /fixer/src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php at line 339
      PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer->fixSpaceAboveClassElement()
        in /fixer/src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php at line 214
      PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer->applyFix()
        in /fixer/src/AbstractFixer.php at line 65
      PhpCsFixer\AbstractFixer->fix()
        in /fixer/src/Runner/Runner.php at line 600
      PhpCsFixer\Runner\Runner->fixFile()
        in /fixer/src/Runner/Runner.php at line 479
      PhpCsFixer\Runner\Runner->fixSequential()
        in /fixer/src/Runner/Runner.php at line 212
      PhpCsFixer\Runner\Runner->fix()
        in /fixer/src/Console/Command/FixCommand.php at line 424
      PhpCsFixer\Console\Command\FixCommand->execute()
        in /fixer/vendor/symfony/console/Command/Command.php at line 341
      [ ... ]
To see details of the error(s), re-run the command with `--sequential -vvv [file]`

wrongly gives the impression that ClassAttributesSeparationFixer is a problem. The fact is, the fixer already got tokens with invalid syntax:

$ docker compose run -e PHP_CS_FIXER_DEBUG=1 php-8.5 php php-cs-fixer check test.php -vvv
PHP CS Fixer 3.92.6-DEV Exceptional Exception by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.5.2

Fixer ordered_class_elements introduced linting issue:

<?php final class Foo {)]
    public function __invoke() {}
    #[Bar(static function () {}
}

@coveralls
Copy link
Copy Markdown

coveralls commented Jan 18, 2026

Coverage Status

coverage: 92.972% (-0.01%) from 92.982%
when pulling 8eb45a8 on 6b7562617765726c6f73:dx-show-which-fixer-breaks-systax
into 1248ada on PHP-CS-Fixer:master.

@kubawerlos
Copy link
Copy Markdown
Member Author

Eh, PHPMD is complaining that "The method fixFile() contains an exit expression." which is what I want to be...

@kubawerlos kubawerlos closed this Jan 18, 2026
@kubawerlos kubawerlos deleted the dx-show-which-fixer-breaks-systax branch January 18, 2026 12:30
@keradus
Copy link
Copy Markdown
Member

keradus commented Jan 18, 2026

i was doing sth similar from time to time. maybe let me reopen and brainstorm

@keradus keradus restored the dx-show-which-fixer-breaks-systax branch January 18, 2026 13:40
@keradus keradus reopened this Jan 18, 2026
Comment thread src/Runner/Runner.php Outdated
} catch (LintingException $e) {
echo "\n\nFixer {$fixer->getName()} introduced linting issue:\n\n{$tokens->generateCode()}\n";

exit(1);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we mimic code from "after-all-rules" validation?

sth similar to:

            try {
                $this->linter->lintSource(...)->check();
            } catch (LintingException $e) {
                $this->dispatchEvent(FileProcessed::NAME, new FileProcessed(FileProcessed::STATUS_LINT));

                $this->errorsManager->report(new Error(Error::TYPE_LINT, $filePathname, $e, $fixInfo['appliedFixers'], $fixInfo['diff']));

                break;
            }

then, last applied is the issue maker.

(i wouldn't always lint rule after rule, it will slow down the process heavily if file requires changes from multiple rules)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wouldn't always lint rule after rule

That is exactly the point: to pinpoint exactly which rule has broken the syntax. It would slow down the process heavily if run on the whole codebase.

Comment thread src/Runner/Runner.php
Comment thread src/Runner/Runner.php
$tokens->clearEmptyTokens();
$tokens->clearChanged();
$appliedFixers[] = $fixer->getName();
if (filter_var(getenv('PHP_CS_FIXER_DEBUG'), \FILTER_VALIDATE_BOOL)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter_...(getenv(...

i guess we can move outside of loop

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it initially as private property of Runner class, but got rid of it to keep all this "debug" in one place.

@keradus keradus merged commit b0b94a5 into PHP-CS-Fixer:master Jan 18, 2026
60 of 61 checks passed
@keradus keradus deleted the dx-show-which-fixer-breaks-systax branch January 18, 2026 19:45
@keradus
Copy link
Copy Markdown
Member

keradus commented Jan 18, 2026

nice addition, @kubawerlos

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants