Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Cs Fixer Laravel Package

fabpot/php-cs-fixer

PHP CS Fixer automatically detects and fixes coding standards issues in your PHP code. It offers built-in rule sets like @PER-CS, @Symfony, and @PhpCsFixer, plus migration rules to modernise your codebase toward newer PHP and PHPUnit versions.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency (never in production):

composer require --dev friendsofphp/php-cs-fixer
# if dependency resolution conflicts with the app's packages:
composer require --dev php-cs-fixer/shim

Bootstrap a config and run it:

./vendor/bin/php-cs-fixer init
./vendor/bin/php-cs-fixer fix --dry-run --diff   # preview
./vendor/bin/php-cs-fixer fix                    # apply

Where to look first

  1. doc/ruleSets/index.rst — start from a set (@PER-CS, @Symfony, @PhpCsFixer, @auto) instead of hand-picking 60 rules.
  2. doc/rules/index.rst — the per-rule catalogue, with "risky" markers and examples.
  3. ./vendor/bin/php-cs-fixer describe <rule-or-set> — the fastest way to understand a rule's options and before/after code. This is the command you'll use daily.

Important Laravel context: Laravel ships Pint, which is a thin opinionated wrapper around PHP CS Fixer. If the project already runs Pint, do not add a second, independently-configured PHP CS Fixer install — pick one. Reach for raw PHP CS Fixer when you need rule granularity, custom rules, or a rule set Pint doesn't expose; keep Pint when the team just wants "Laravel style, zero decisions".

First real use case: lock in a baseline on a fresh/legacy Laravel app — commit the config, run fix once in a dedicated commit ("style: apply php-cs-fixer"), then only ever run check in CI so diffs stay reviewable.

Implementation Patterns

Baseline config (.php-cs-fixer.dist.php)

<?php

use PhpCsFixer\Config;
use PhpCsFixer\Finder;
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;

$finder = Finder::create()
    ->in([
        __DIR__.'/app',
        __DIR__.'/config',
        __DIR__.'/database',
        __DIR__.'/routes',
        __DIR__.'/tests',
    ])
    ->exclude(['bootstrap/cache', 'storage'])
    ->notName('*.blade.php')          // critical: never parse Blade
    ->notPath('_ide_helper.php')
    ->ignoreDotFiles(true)
    ->ignoreVCS(true);

return (new Config())
    ->setParallelConfig(ParallelConfigFactory::detect())
    ->setRiskyAllowed(false)          // opt in deliberately, see Gotchas
    ->setRules([
        '@PER-CS' => true,
        // explicit overrides after the set:
        'ordered_imports' => ['sort_algorithm' => 'alpha'],
        'no_unused_imports' => true,
        'single_quote' => true,
        'trailing_comma_in_multiline' => [
            'elements' => ['arrays', 'arguments', 'parameters'],
        ],
        'yoda_style' => false,        // team preference, avoids churn
    ])
    ->setFinder($finder)
    ->setCacheFile(__DIR__.'/.php-cs-fixer.cache');

Commit .php-cs-fixer.dist.php; keep .php-cs-fixer.cache in .gitignore.

Composer scripts

"scripts": {
    "lint": "php-cs-fixer check --diff",
    "lint:fix": "php-cs-fixer fix"
}

composer lint should be the same command the CI job runs — one source of truth.

CI (GitHub Actions)

- uses: shivammathur/setup-php@v2
  with:
    php-version: '8.3'
    tools: composer:v2
- run: composer install --no-interaction --prefer-dist
- run: vendor/bin/php-cs-fixer check --diff --format=github

Rely on the exit code (non-zero when changes are needed), not on parsing output. --format=github annotates the PR diff; checkstyle/junit/json exist for other CI systems. Cache the .php-cs-fixer.cache file keyed on PHP version + diff of the config to cut minutes off large repos.

Pre-commit hook on staged files only

#!/bin/sh
FILES=$(git diff --cached --name-only --diff-filter=ACM \
  | grep -E '\.php$' | grep -v '\.blade\.php$')

[ -z "$FILES" ] && exit 0

vendor/bin/php-cs-fixer fix --path-mode=intersection $FILES || exit 1
git add $FILES

--path-mode=intersection is mandatory here: it intersects your passed paths with the configured Finder, so a stray vendor/ or storage/ path can't get rewritten.

Day-to-day workflows

  • Single file, fast loop: ./vendor/bin/php-cs-fixer fix app/Http/Controllers/OrderController.php
  • Explore a rule without touching config: ./vendor/bin/php-cs-fixer fix --rules='{"@PER-CS":true,"yoda_style":false}' --dry-run --diff app/
  • See who changed what: --verbose prints applied fixers per file; -vvv shows which rules produced each change — invaluable when a fix looks surprising.
  • Modernisation as a separate PR: @autoPHPMigration / @autoPHPMigration:risky (and @autoPHPUnitMigration:risky for tests) rewrite syntax toward newer PHP/PHPUnit. Run these in their own commit, with the test suite green before and after.
  • Editor integration: PhpStorm has native support; VS Code has junstyle.vscode-php-cs-fixer. Point the editor at the same .php-cs-fixer.dist.php used by CI so format-on-save and the hook never disagree.
  • Docker / Sail: run sail exec -it laravel.test vendor/bin/php-cs-fixer fix; keep the cache file on a real filesystem mount, and consider hardcoding new ParallelConfig(4) instead of detect() in containers with many host CPUs exposed.

Gotchas and Tips

Blade files will be corrupted. .blade.php is valid PHP-ish enough that the tokenizer may accept it, but directives and HTML get mangled. Always ->notName('*.blade.php'), or scope the Finder to app/, config/, database/, routes/, tests/.

Risky rules are silently inert. With setRiskyAllowed(false) (the default), rules like declare_strict_types, strict_comparison, void_return, mb_str_functions, psr_autoloading, no_unneeded_final_method are skipped without error. If a rule "does nothing", check the risky badge in describe. Then judge each one against Laravel reality: declare_strict_types can break implicit type juggling in request payloads and config values; strict_comparison will rewrite == you may have written intentionally. Prefer @PER-CS:risky piecemeal over wholesale.

Pint and PHP CS Fixer fight each other. Two configs with overlapping-but-different rules produce flip-flopping diffs (each tool reverts the other). Pick one runner; if you keep Pint, PHP CS Fixer is still installed as its transitive dependency, so never script both pint and php-cs-fixer.

Stale cache after config or version changes. The cache keys on rules + file hashes, but after a composer update of the fixer or a puzzling "no changes" result, run --using-cache=no or delete .php-cs-fixer.cache. In CI, either restore a correctly-keyed cache or disable it.

CLI order is not execution order. Fixers execute by internal priority, not by the order you list them in setRules(). Listing a rule after a set does override the set's options for that rule, but genuinely incompatible pairs (e.g. blank_line_after_opening_tag vs linebreak_after_opening_tag, or several phpdoc_* combinations) will warn/conflict — resolve by removing one, not by reordering.

Paths are resolved relative to the config file. Finder::create()->in([...]) with relative paths behaves differently depending on the CWD you invoke from. Use __DIR__ in the config and --config=.php-cs-fixer.dist.php when running from outside the project root.

PHP version support is a hard gate. Supported range moves over time (currently 7.4–8.5). Running on a newer PHP than supported fails fast; for local experiments only, use --allow-unsupported-php-version=yes or PHP_CS_FIXER_IGNORE_ENV=1. In CI, run the fixer on the same PHP minor as the app to avoid syntax the runtime can't parse.

Semantics-adjacent fixers to review in Laravel apps:

  • ordered_class_elements — large, noisy diffs; can interleave oddly with trait use blocks and constants. Introduce alone.
  • binary_operator_spaces with align — causes perpetual churn on long arrays; use single_space if you want stable diffs.
  • no_unused_imports / fully_qualified_strict_types — safe in v3 (annotations and attributes are understood), but confirm files that reference classes only inside strings (some service providers, phpstorm.meta.php) still resolve.
  • header_comment — conflicts with blank_line_after_opening_tag if configured with a leading newline; set 'separate' => 'bottom' deliberately.

Speed tips. Parallel mode is the single biggest win on big codebases; ParallelConfigFactory::detect() sizes to CPU count. For one-off checks, --dry-run still writes cache — combine --using-cache=no for throwaway experiments so you don't poison the cache with a temporary --rules set.

Debugging a wrong fix. Reproduce in isolation: php-cs-fixer fix --rules='{"the_suspect_rule":true}' --dry-run --diff path/to/file.php, then consult describe. If the rule is buggy, pin a version in composer.json and open an issue — the release notes show a steady stream of edge-case fixes (ClassDefinitionFixer, StatementIndentationFixer, PHP 8.4 property hooks), so upgrading promptly is usually the resolution.

Extension points. Custom fixers implement PhpCsFixer\Fixer\FixerInterface and register via $config->registerCustomFixers([new MyFixer()]); custom rule sets via RuleSet. This is genuinely useful for house rules (e.g. banning dd() in committed code, enforcing a company header) — but only consider it after exhausting the built-in catalogue, and cover custom fixers with the package's AbstractFixerTestCase so upgrades don't silently break them.

Don't self-update in a Composer install. That path is for the PHAR distribution; manage upgrades with composer update friendsofphp/php-cs-fixer --with-dependencies, then re-run check before merging to see the diff a version bump introduces.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core