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

Coding Standard Laravel Package

interaction-design-foundation/coding-standard

A shared PHP coding standard from Interaction Design Foundation for Laravel/PHP projects. It packages PHP_CodeSniffer rules so teams can enforce consistent style and catch common issues with minimal configuration, standardizing local and CI checks across apps and packages.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the whole toolchain, and check your PHP version first.

php -v   # must be 8.4+; 1.0.0 requires PHP ^8.4 and PHP_CodeSniffer ^4.0
composer require --dev interaction-design-foundation/coding-standard:^1.0
composer require --dev squizlabs/php_codesniffer:^4.0 friendsofphp/php-cs-fixer rector/rector

The package still ships configuration, not the binaries — but as of 1.0.0 the split of responsibilities changed fundamentally:

  • PHP-CS-Fixer is the primary tool. It owns all formatting, based on PER-CS 3.0, and auto-fixes everything.
  • PHP_CodeSniffer is supplementary. Roughly 50 sniffs were removed — the entire PSR-12 ruleset plus array formatting, whitespace/spacing, string quoting, use-statement ordering. What remains is what a fixer can't express: structure, semantics, Laravel conventions, naming, complexity.
  • Rector joins the toolchain and is required for one specific migration (see gotchas).

PHPCS alone is no longer a complete standard. If you wire only phpcs into CI you will silently stop enforcing formatting.

Where to look first, in this order:

  1. composer.json — confirm the ^8.4 / ^4.0 constraints and whether it pulls dealerdirect/phpcodesniffer-composer-installer (needed only if you want to refer to the standard by name).
  2. The PHP-CS-Fixer section of the README — the entry point is now a factory: Config::create(__DIR__). No more copying a flat array.
  3. ruleset.xml — read it as a semantic ruleset now. Expect naming, complexity, structure, Laravel sniffs. Don't go looking for spacing rules; they're not there.
  4. docs/README.md — custom sniffs documented in one place, including the previously undocumented Functions.MissingOptionalArgument.

First use case — replace your fixer config, then look before you leap:

// .php-cs-fixer.dist.php
<?php
use InteractionDesignFoundation\CodingStandard\Config;

return Config::create(__DIR__);
vendor/bin/php-cs-fixer fix --dry-run --diff | less   # read this before applying
vendor/bin/phpcs -i                                    # confirm registered standard name
vendor/bin/phpcs src/                                  # with your phpcs.xml in place

Run it on a throwaway branch and expect a large, mostly mechanical diff — member ordering, docblock collapsing, import changes, native casts.

Implementation Patterns

1. Let the shared config own the fixer; override only the finder. The factory takes your project root, so paths resolve correctly. Take the returned Config object and mutate it rather than rebuilding from scratch:

<?php
use InteractionDesignFoundation\CodingStandard\Config;
use PhpCsFixer\Finder;

$config = Config::create(__DIR__);

return $config
    ->setFinder(
        Finder::create()
            ->in([__DIR__ . '/src', __DIR__ . '/tests', __DIR__ . '/database'])
            ->exclude(['vendor', 'var', 'storage'])
            ->notPath('bootstrap/cache')
    );

If the factory already sets a finder, setFinder() replaces it — that's what you want, since every project has different exclusions. Keep setRiskyAllowed(true) implicit: 1.0.0 turns the risky presets (@PHP8x4Migration:risky, @PHPUnit10x0Migration:risky) on by default.

2. Keep phpcs.xml thin — and delete formatting overrides. They reference sniffs that no longer exist and will fail to resolve:

<?xml version="1.0"?>
<ruleset name="MyProject">
    <description>Semantic checks only; formatting is PHP-CS-Fixer's job.</description>

    <file>src</file>
    <file>tests</file>

    <rule ref="IxDFCodingStandard"/>

    <exclude-pattern>*/migrations/*</exclude-pattern>
    <exclude-pattern>*/generated/*</exclude-pattern>
</ruleset>

Anything you previously did here for line length, array syntax, or import ordering should be removed. The upgrade note is explicit: remove any formatting sniff overrides that no longer exist.

3. Wire composer cs to run both, in the right order. The package chains PHP-CS-Fixer then phpcbf, identically locally and in CI. Mirror that, and add a check-only variant for pipelines:

"scripts": {
    "cs":       ["@php-cs-fixer", "@phpcbf", "@phpcs"],
    "cs:check": ["@php-cs-fixer --dry-run --diff", "@phpcs"],
    "phpcs":    "phpcs",
    "phpcbf":   "phpcbf",
    "php-cs-fixer": "php-cs-fixer fix",
    "rector":   "rector"
}

4. Add Rector, because one rule was deliberately delegated to it. php_unit_strict is disabled in the fixer; the assertEquals → assertSame rewrite is now handled by Rector's AssertEqualsToSameRector, which only rewrites provably-scalar assertions and therefore won't break object/array comparisons:

// rector.php
return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
    ->withRules([Rector\PHPUnit\Rector\MethodCall\AssertEqualsToSameRector::class]);

This is the correct replacement. Do not re-enable php_unit_strict — you'd reintroduce the broken-object-comparison bug the split was designed to avoid.

5. Adopt the mechanical diff as one isolated commit and ignore it in blame. Because the fixer now owns formatting, ordered_class_elements, single-line docblocks, global_namespace_import, and native casts will all land at once. Do it deliberately:

  1. Branch off, run composer cs, commit the reformat on its own with no behavioural changes.
  2. Add that commit hash to .git-blame-ignore-revs and configure git config blame.ignoreRevsFile .git-blame-ignore-revs.
  3. Merge it quickly, then let feature branches rebase.

This keeps git blame usable and makes review tractable — reviewers can skip the mechanical commit entirely.

6. Replace your two style CI workflows with the single auto-fix one. 1.0.0 ships a copyable .github/workflows/coding-standard.yml that runs Rector, PHP-CS-Fixer and phpcbf, then commits fixes back via stefanzweifel/git-auto-commit-action v7. Copy it verbatim rather than writing your own — the value of the package is that every consumer's pipeline looks the same:

- run: composer install --prefer-dist --no-progress
- run: composer cs:check

Use --report=checkstyle / --format=checkstyle and feed it to your CI's annotation format for inline PR comments.

7. Split editor duties to match the tools. Enable PHP-CS-Fixer on save for formatting; keep PHPCS inspections for the semantic layer with "Show sniff name" on. Developers see IxDFCodingStandard.… or Functions.MissingOptionalArgument inline and fix it immediately instead of reading CI logs.

Gotchas and Tips

This is a hard breaking release; treat the upgrade as a project, not a bump. PHP ^8.4 and PHPCS ^4.0 are non-negotiable. Pin ^1.0 and schedule the diff review — it won't fit in a lunch break. The documented upgrade path is: bump PHP and the package → swap the fixer config for Config::create(__DIR__) → keep <rule ref="IxDFCodingStandard"/> and delete dead overrides → run composer cs and review.

PHPCS 4 breaks custom sniffs. The 4.x tokenizer API changed and several sniffs moved or were renamed. If you maintain an in-house sniff written against 3.x, it will not run. Audit that before upgrading, not after.

Risky rules are now on by default. The @PHP8x4Migration:risky and @PHPUnit10x0Migration:risky presets are enabled, so the fixer will touch declare(strict_types), casts, and comparisons without you opting in. phpcbf remains conservative, but the fixer does not — always read --dry-run --diff output on a branch you haven't reviewed.

Test method names become snake_case. php_unit_method_casing is set to snake_case and the PSR-1 CamelCaps sniff is excluded for tests/. Every existing testSomethingWorks() will be rewritten. Get the team's agreement first, then land it in the mechanical commit alongside the rest — not sprinkled through feature branches.

Line length is now 180 warning / 220 error, up from a hard 120. If you had a Generic.Files.LineLength property override, it probably still resolves, but check whether you actually want to reimpose a tighter limit — and remember the fixer doesn't wrap code, so PHPCS is your only line-length signal.

PHPCS alone is a trap. A green phpcs run tells you almost nothing now. The most common failure mode after upgrading is a CI job that still only runs PHPCS while formatting silently rots. composer cs or nothing.

Run the fixer before PHPCS, always. Formatting-then-semantics is the order composer cs uses and the order you should use manually. Reversing it produces PHPCS reports about code the fixer is about to change.

--standard=IxDFCodingStandard still depends on installed_paths. The 1.0.0 docs use the name, but if dealerdirect/phpcodesniffer-composer-installer is blocked by your security policy you get "the coding standard … is not installed." The explicit ruleset.xml path always works. Verify with vendor/bin/phpcs -i.

Exclude generated code in both configs — they don't share. Migrations, Doctrine proxies, compiled Blade views, var/, storage/, .php-cs-fixer.cache. Set exclude-pattern in phpcs.xml and ->exclude() in the Finder. Forgetting the fixer side is worse now that it owns formatting, since it will rewrite files you never intended to touch.

Debugging: phpcs -s appends sniff codes (essential for targeted // phpcs:ignore Functions.MissingOptionalArgument -- reason comments); phpcs -e lists every sniff in the standard; php-cs-fixer fix --dry-run --diff -vvv shows which rule triggered each change. Prefer phpcs:ignore with a trailing reason over blanket disables.

Scope the fixer when running ad hoc. php-cs-fixer fix src/Foo applies the full config but only over that path; pass --path-mode=intersection when you want it constrained to your finder and the given paths.

Functions.MissingOptionalArgument may surprise Laravel teams. It flags calls that rely on defaulted parameters — convenient in plain PHP, noisy around framework APIs that intentionally use defaults. It's documented now in docs/README.md; if it's too broad for your codebase, exclude it project-wide in phpcs.xml rather than forking.

Extension points, in increasing cost:

  • Mutate the Config object returned by Config::create() (finder, extra rules, setRules merges) — cheapest, and upstream additions still reach you.
  • <exclude-pattern> / <exclude name="..."> in phpcs.xml — per-project carve-outs for the semantic layer.
  • // phpcs:ignore for one-offs, with a reason after --.
  • A local sniff in src/Standards/, referenced by relative path. Still viable, still documented, but now genuinely rare — most formatting complaints belong in the fixer config, not a new sniff.

Don't fork. Single maintainer org, low star count: treat it as an internal standard published for convenience. Pin the version and read the changelog before composer update — with formatting concentrated in one tool, an upstream ruleset change is a repo-wide reformat waiting to land in someone's feature branch.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource