Cycle between `braces_position` and `single_line_empty_body` on empty named bodies

Author: bergtungaCreated May 12, 2026Updated Sep 5, 2026
Labelskind/bugstatus/to verify

Problem description

braces_position and single_line_empty_body form a no-op cycle on empty named-class bodies. braces_position expands ) {} to ) {\n }, then single_line_empty_body collapses it back. Both rules ship in @PhpCsFixer. Net diff contribution is zero, but both rules land in appliedFixers whenever another fixer rewrites the file.

Example has unrelated brace fix (class opening brace on the wrong line) alongside an empty named-method body with a multi-line signature. A full @PhpCsFixer run lists class_definition, braces_position, and single_line_empty_body in appliedFixers. Running class_definition alone produces a identical result but only lists class_definition in appliedFixers.

I think this is a bug rather than misconfiguration because both rules are part of @PhpCsFixer itself. No other ruleset is layered on top. Past cyclical-rule conflicts in this project have been treated as bugs and fixed. See similar subsection

Possible fix

braces_position already has allow_single_line_empty_anonymous_classes and allow_single_line_anonymous_functions for the anonymous cases. A named-body equivalent, allow_single_line_empty_function_body, would resolve this. When enabled, braces_position would treat ) {} on named bodies as already valid and not report a fix.

Not sure I like this, because without that config, it's still incompatible.

Similar

  • #1655 (ParenthesisFixer and SpacesAfterSemicolonFixer on for($i=0;$i<$c;), resolved by #1684)
  • #1822 (no_empty_comment and single_blank_line_before_namespace): Introduced incompatibility feature

Confirmed non-duplicates

  • #7298: single_line_empty_body contradicts PSR-12. Closed not-planned. That report was specifically about layering @PSR12 + @PhpCsFixer. My case is @PhpCsFixer on its own.
  • #7962: proposed only_for_constructors config for single_line_empty_body. Closed unmerged. Adjacent issue, but approaches it from the single_line_empty_body side.
  • #9329: recent braces_position change for anonymous functions in PSR rulesets. Different body kind.

Minimal reproducer CLI command

bash
# A. Full @PhpCsFixer
php-cs-fixer fix Repro.php --rules=@PhpCsFixer --dry-run -vvv 
# B. class_definition alone
php-cs-fixer fix Repro.php --rules=class_definition --dry-run -vvv

Minimal reproducer code snippet

Repro.php as written (class brace on the same line as the class keyword):

php
<?php

class Repro {
    public function __construct(
        bool $a,
    ) {}
}

Both runs below produce the same result:

php
<?php

class Repro
{
    public function __construct(
        bool $a,
    ) {}
}

But running the full @PhpCsFixer on Repro.php reports all 3 as having run:

   1) Repro.php (class_definition, braces_position, single_line_empty_body)

Fixer version

3.94.2 7th Gear

PHP version

8.2.29

How do you run Fixer?

Composer package

Contribution Checks

  • I have verified if this problem was already reported
  • I am familiar with "Feature or bug?"

Source: PHP-CS-Fixer/PHP-CS-Fixer