Skip to content

Fix fatal error when configuring a PHP-CS-Fixer fixer - #62

Open
TomasVotruba wants to merge 2 commits into
mainfrom
reproduce-configured-fixer-fatal
Open

Fix fatal error when configuring a PHP-CS-Fixer fixer#62
TomasVotruba wants to merge 2 commits into
mainfrom
reproduce-configured-fixer-fatal

Conversation

@TomasVotruba

@TomasVotruba TomasVotruba commented Aug 7, 2026

Copy link
Copy Markdown
Member

Fixes #44 and covers it in CI.

Cause

The bug does not need the scoped/prefixed release build - it reproduces on plain source, because composer.json has "replace": {"symfony/console": "*"}, so Symfony\Component\Console\Application is never installed.

Configuring a fixer whose option is deprecated hits ConfigurableFixerTrait::configure(), which calls PhpCsFixer\Console\Application::getMajorVersion(). That class extends the missing Symfony console Application, and PHP must resolve the parent class before the static call:

return ECSConfig::configure()
    ->withConfiguredRule(NullableTypeDeclarationForDefaultNullValueFixer::class, [
        'use_nullable_type_declaration' => false,
    ]);
PHP Fatal error:  Uncaught Error: Class "Symfony\Component\Console\Application" not found
  in vendor/friendsofphp/php-cs-fixer/src/Console/Application.php:51
#2 vendor/friendsofphp/php-cs-fixer/src/Fixer/ConfigurableFixerTrait.php(67): PHP_CodeSniffer\Autoload::load()
#3 src/Config/ECSConfig.php(391): ...NullableTypeDeclarationForDefaultNullValueFixer->configure()

In the released package the very same class is reported under its prefixed name, ECSPrefix202607\Symfony\Component\Console\Application.

Fix

Ship a declaration-only stub in /stubs, autoloaded via classmap. ECS never runs the php-cs-fixer console, so only the class declaration is needed.

php-scoper prefixes the stub along with everything else, so the release build gets ECSPrefix<YYYYMM>\Symfony\Component\Console\Application - exactly the name php-cs-fixer's Application extends there (verified by running php-scoper over /stubs with this repo config). stubs is added to the downgrade and scoping steps of the build workflow.

CI

New Configured Fixer workflow runs bin/ecs check with a configured fixer and asserts the run produces output instead of fatalling. It was red on the first commit of this PR and is green after the fix.

before:

PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Application" not found

after:

1) build/nested/some_file.php
    ---------- begin diff ----------
@@ -1 +1,3 @@
-<?php  $x=1;
+<?php
+
+$x = 1;
    ----------- end diff -----------

Note on the failing Code Analysis job

PHPStan and Rector fail on this branch, but not because of it - composer.lock is gitignored, so CI always resolves the latest dev tools. On main, with today's versions, the same two failures appear:

  • PHPStan: Multiple services of type Rector\TypePerfect\Reflection\MethodNodeAnalyser found (DI conflict inside rector/type-perfect)
  • Rector: 6 files with readonly class changes proposed by the newer Rector, all untouched by this PR

Covers #44 - configuring a fixer calls PhpCsFixer\Console\Application::getMajorVersion(), which extends the replaced symfony/console Application and fatals.
…rs do not fatal

PhpCsFixer\Console\Application extends Symfony\Component\Console\Application, which ECS replaces and never installs. ConfigurableFixerTrait::configure() calls its static getMajorVersion(), so PHP has to resolve the parent class. Shipping a declaration-only stub in /stubs makes it resolvable, in both plain source and the prefixed release build.
@TomasVotruba TomasVotruba changed the title Add CI reproducer for configured PHP-CS-Fixer fixer fatal error Fix fatal error when configuring a PHP-CS-Fixer fixer Aug 7, 2026
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.

Class "ECSPrefix202607\Symfony\Component\Console\Application" not found

1 participant