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

Easy Coding Standard Laravel Package

symplify/easy-coding-standard

Easy Coding Standard runs PHP_CodeSniffer and PHP-CS-Fixer rules together through one simple PHP config file. Install on any PHP 7.2–8.5 project, get parallel speed out of the box, use prepared sets, and fix code with a single command.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev symplify/easy-coding-standard
    
  2. Initialize Config:

    vendor/bin/ecs init
    

    Generates ecs.php with a PSR-12 baseline.

  3. First Run:

    vendor/bin/ecs check src/
    

    Fix issues automatically:

    vendor/bin/ecs check src/ --fix
    
  4. Pick your engine: ECS ships both the PHP engine and blink. As of 13.3.7 blink has full rule parity — PsrAutoloadingFixer was the last unported rule and is now available. That makes blink a viable default for day-to-day runs rather than a "mostly works" experiment.

Key First Use Case

Integrate into CI/CD (e.g., GitHub Actions):

- name: Run ECS
  run: vendor/bin/ecs check src/ --no-interaction --diff

Add to composer.json scripts:

"scripts": {
    "cs-check": "ecs check src/ --no-interaction --diff",
    "cs-fix": "ecs check src/ --fix --no-diffs"
}

Note the --no-diffs on the fix script — see Gotchas.


Implementation Patterns

Core Workflows

  1. Project-Wide Enforcement:

    // ecs.php
    return static function (ECSConfig $ecsConfig): void {
        $ecsConfig->paths([
            __DIR__.'/app',
            __DIR__.'/src',
            __DIR__.'/routes',
            __DIR__.'/database',
        ]);
        $ecsConfig->sets([
            SetList::PSR_12,
            SetList::PER_CS,
        ]);
        $ecsConfig->skip([
            __DIR__.'/bootstrap/cache',
        ]);
    };
    
  2. Per-Module Rules (for large apps):

    $ecsConfig->paths([__DIR__.'/modules/auth']);
    $ecsConfig->rules([
        NoUnusedImportsFixer::class,
        SingleImportPerStatementFixer::class,
        NullableTypeDeclarationFixer::class,
    ]);
    

    These three are worth calling out: they were among the fixers whose configuration blink used to silently ignore. If you configure them (or ModifierKeywordsFixer), blink now actually honours the config.

  3. Custom Rulesets:

    $ecsConfig->ruleWithConfiguration(
        ClassNameLengthRule::class,
        ['max' => 30]
    );
    

Integration Tips

  • Blink parity upgrade pattern: because five fixer configs are now modelled rather than dropped, the first blink run after upgrading can report new violations in files that previously passed. Run it as a standalone fix commit before merging anything else, so the diff is reviewable.
  • Import grouping under PER_CS: the set now reliably keeps a blank line between the class-import group and use function / use const groups. If your codebase currently has no separation, expect one clean-up pass; after that it's stable.
  • Autoloading correctness: PsrAutoloadingFixer derives the expected class name from the file path, so run it with the real project root (not a copied temp dir) or it will compute the wrong FQCN.
  • CI Optimization:
    vendor/bin/ecs check --parallel --cache
    
  • Git Hooks: auto-fix on commit, quietly:
    vendor/bin/ecs check --fix --no-diffs --skip=tests
    
  • Pre-PR script: use --fix with diffs locally to eyeball what changed, --no-diffs in automation.

Gotchas and Tips

Pitfalls

  1. --fix is now chatty: --fix prints a diff per fixed file plus the applied checkers, then the summary — gated behind --no-diffs. This is great for local review and terrible for a 300-file pre-commit hook or CI log. Always pair --fix with --no-diffs in automation.

  2. Timing format is conditional: Runs under 5s print milliseconds (9952ms-style), runs of 5s or more print seconds with two decimals (9.95 s). Any log scraper or CI metric regex keyed on ms will break after the first slow build. Match on the numeric part, not the unit.

  3. Config modelling changes behaviour: Rules whose configuration was previously unmodelled (ModifierKeywordsFixer, SingleImportPerStatementFixer, NullableTypeDeclarationFixer, and others) will now change files they used to leave alone under blink. Pin the version in composer.lock and roll this upgrade deliberately.

  4. Conditional @return docblocks: RemoveSuperfluousReturnNameFixer no longer strips the condition variable from PHPStan conditional return types (@return $arr ? A : B). If an earlier version ran over your codebase, audit the docblock diff — corruption is silent and only bites when PHPStan stops resolving the type.

  5. Import blank lines in PER_CS: Two fixers fight over the same whitespace (BlankLineBetweenImportGroupsFixer vs NoBlankLineBetweenImportsFixer). The priority bug is fixed, but if you maintain a custom ruleset that re-enables the lower-priority fixer at an explicit priority you can reintroduce the loop.

  6. Laravel-specific quirks:

    • Exclude Blade: $ecsConfig->exclude([__DIR__.'/resources/views']);
    • Add __DIR__.'/app/Console/Commands' explicitly if it's outside your default paths.
    • Skip generated/handler code rather than overriding PSR_12 rules:
      $ecsConfig->skip([__DIR__.'/app/Exceptions/Handler.php']);
      
  7. PHP version mismatches: ECS 13+ requires PHP 8.1+. On Laravel 7 / PHP 7.4, pin ~12.6:

    composer require symplify/easy-coding-standard:^12.6
    

Debugging

  • vendor/bin/ecs check --verbose — full per-file trace.
  • vendor/bin/ecs check --no-diffs --fix — confirm whether a change happened without the diff noise.
  • When blink and PHP disagree, run the same paths through both engines; parity is now claimed complete, so any divergence is a bug worth reporting.
  • Run git diff --stat after a fresh upgrade fix pass to spot unexpectedly large changes caused by newly honoured configs.

Extension Points

  1. Custom Rules:
    $ecsConfig->rule(CustomLaravelRule::class);
    
  2. Path-aware fixers: the token stream now carries a per-file path set by the runner, with the Fixer interface unchanged. Custom fixers (or ports of PHP-CS-Fixer rules that need the filename, as PsrAutoloadingFixer did) can read it instead of threading the path through manually.
  3. Dynamic Configs:
    $ecsConfig->paths(array_filter([env('ECS_PATHS', __DIR__.'/src')]));
    
  4. Output Formats:
    vendor/bin/ecs check --format=checkstyle > ecs-report.xml
    

Pro Tips

  • Incremental adoption: start with --fix on a narrow path, widen paths only after the config-modelling upgrade settles.
  • Team alignment: pin the ECS version in composer.lock and run ecs --version in CI — output formatting (diff bodies, elapsed units) is now release-sensitive enough that mixed versions produce noisy diffs between machines.
  • Performance: exclude vendor/ and node_modules/; prefer blink for full-project runs and the PHP engine when you need to debug a specific rule.
  • Laravel Artisan Integration:
    // app/Console/Commands/ECSCommand.php
    public function handle() {
        $exitCode = (new ECS())->run();
        exit($exitCode);
    }
    
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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log