I was working on a legacy PHP WooCommerce plugin that had inconsistent formatting - some files used tabs, others spaces, brace styles were all over the place. Rather than manually fixing thousands of lines, I used php-cs-fixer to enforce consistent PHP coding standards across the entire codebase.

Check for issues:

php-cs-fixer check .

Fix them:

php-cs-fixer fix .

You can also run it on specific directories:

php-cs-fixer fix Plugin/

To check PHP syntax without fixing anything:

php -l myfile.php

I also tried using Prettier with the PHP plugin:

npm install prettier @prettier/plugin-php

But php-cs-fixer handles PHP-specific conventions better. It understands PSR-12, knows about PHP 8 features, and has rules for things like import order that Prettier just doesn’t handle.

Configuration Link to heading

Create a .php-cs-fixer.php config file to customise the rules:

<?php

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__)
    ->exclude('vendor')
    ->exclude('node_modules');

$config = new PhpCsFixer\Config();
return $config->setRules([
        '@PSR12' => true,
        'array_syntax' => ['syntax' => 'short'],
        'ordered_imports' => ['sort_algorithm' => 'alpha'],
        'no_unused_imports' => true,
        'single_quote' => true,
        'trailing_comma_in_multiline' => true,
    ])
    ->setFinder($finder);

PSR-12 is a solid baseline (it’s the modern PHP standard), with some extra rules layered on - short array syntax, alphabetically sorted imports, and trailing commas in multiline arrays. The trailing comma rule is particularly nice because it makes diffs cleaner when you add array items.

CI integration Link to heading

Add this to your GitHub Actions workflow:

- name: Check PHP formatting
  run: |
    composer global require friendsofphp/php-cs-fixer
    php-cs-fixer check --diff --dry-run

The --diff flag shows what would change, and --dry-run makes it fail without modifying files. Perfect for PR checks.

In pre-commit hooks, I usually skip php-cs-fixer because it’s a bit slow on large codebases. Instead, I run it as a CI check and let developers fix formatting issues before pushing.