php-collective/code-sniffer
A PHP_CodeSniffer ruleset that follows PSR-2 and PSR-12 with many extra fixers on top, plus a stricter PhpCollectiveStrict standard. Install via Composer, add it to phpcs.xml, and run phpcs/phpcbf or composer scripts to check and auto-fix code style.
phpcs (detect) and phpcbf (auto-fix) are cleanly separated, you can decide to ship a reporting gate first and a blocking gate later, without re-tooling. This is a phased rollout decision, not an all-or-nothing one.PreferCastOverFunction mangled first-class callables (strval(...)) into a parse error, DocBlockParamAllowDefaultValue appended |array to params already narrowed to non-empty-array/non-empty-list/list, and DocBlockThrows resolved same-namespace exceptions as global (\LocalException instead of \App\LocalException). This is the single most important input into "can we run phpcbf in bulk on a branch, or only one file at a time with human review." Patch-level autofix correctness is now a tracked adoption criterion, not an assumed property.PhpCollective and the stricter PhpCollectiveStrict, which adds parameter/property/return type-hint enforcement) let you sequence adoption: formatting and whitespace first, type-hint strictness after the codebase is clean. That maps directly to a multi-quarter "raise the floor" roadmap rather than a single migration.Modernize.FunctionCalls.Dirname, and a PHP ≥ 8.1 floor. Its presence is evidence that a modernize-and-lint workstream is tractable now rather than after a framework upgrade.@param/@return accuracy, and self/static references. Two of the three 0.6.9 fixes land squarely in this area, which is a useful signal: docblock rules are the highest-churn, highest-bug-density part of the ruleset. Adopting it is effectively a decision that docblocks are a maintained contract, not decoration — relevant if you publish packages or generate API docs.phpcbf in dry-run/report mode against an existing codebase to size the cleanup backlog before committing engineering time to it. Budget for finding-count drift between patch versions (see below) so the backlog number is not mistaken for a stable metric.Consider it when:
squizlabs/php_codesniffer (this is a ruleset, not a replacement for the underlying tool).require-dev dependency. Patch releases can change both the fixes applied and the findings reported; treat version bumps as reviewable changes with a diff of phpcs output on a representative repo.phpcbf output straight to trunk. 0.6.9 shows the fixer is actively being hardened, which is good, but it also shows fixer output is not yet a stability guarantee.Look elsewhere when:
throw new Sub\NestedException()) were previously skipped by DocBlockThrows and are now reported like any other missing @throws tag. Expect new findings on upgrade. If your CI gate is blocking and you do not control when the ruleset version moves, that is a surprise-red-build risk; pinning solves it, floating constraints do not.Adoption recommendation: time-boxed spike on one repository, report-only mode, measure finding volume and auto-fix coverage. Only promote to a blocking CI gate if the fixable-to-manual finding ratio is high enough that the team is not paying down noise. Add one gate before that promotion: run phpcbf across the spike repo on a branch, require a green test suite and a clean php -l pass on every touched file, and eyeball the diff. The 0.6.9 fixes raise confidence in the fixers, but they do not yet justify blind application.
For executives (one paragraph). This is a free, MIT-licensed developer tool that mechanically enforces a consistent PHP coding style across the codebase. It adds no runtime dependency, no infrastructure, and no customer-facing risk — it lives in require-dev and runs in CI and in developers' editors. The business case is review efficiency and consistency: it converts style debates into automated fixes, which shortens pull-request cycles and reduces onboarding friction. Cost is a one-time configuration effort plus a low, ongoing maintenance cadence. The main caveat is that it is a small, low-adoption community package; we mitigate by pinning a version, treating an upgrade as a reviewed change, and treating the tool as replaceable tooling that sits behind a config file, not as deep architectural lock-in. The latest patch release (0.6.9) is reassuring in one specific way: three bugs in its automatic code-rewriting were found and fixed, including one that could corrupt valid code — the project is being hardened, and we are gating our rollout on a branch-and-review step rather than trusting auto-fix blind.
For engineering leads. 251 sniffs, PSR-2/PSR-12-compliant baseline, with phpcbf auto-fixing the majority of violations. Ships a PhpCollective standard and a stricter PhpCollectiveStrict tier for incremental tightening. Integrates via a single phpcs.xml ruleset reference, with Composer script shortcuts and IDE external-tool wiring documented. The upstream project self-reports PHPStan level 8, which is a reasonable proxy for internal quality. Recent patches (0.6.8 → 0.6.9) tightened three fixers: first-class callable syntax is no longer rewritten by PreferCastOverFunction, narrowed array types are recognized by DocBlockParamAllowDefaultValue, and DocBlockThrows now resolves exception names against the current namespace. One of those is a deliberate behavior change — qualified relative names like Sub\NestedException are now reported — so budget for a findings delta when you bump the pin, and diff phpcs output on a sample repo as part of the bump.
For the team. Two commands, phpcs to check and phpcbf to fix; hotkeys in the editor; a ruleset file at repo root. Rollout is report-first, then blocking. We silence rules deliberately and in code review, not by disabling the tool. Auto-fix runs on a branch with tests and a lint pass before merge; it does not run straight to trunk. When you upgrade the ruleset version, expect the finding count to move in either direction — that is the tool improving, not your code regressing.
Honest risk framing to state up front. Low stars and zero dependents mean we should assume we may need to fork or swap it. The mitigation is architectural, not contractual: keep all style configuration in one ruleset file, never let the tool's opinions leak into application design, and re-evaluate annually against Laravel Pint / PHP-CS-Fixer as the ecosystem default. Auto-fix correctness is the residual risk to watch — 0.6.9 fixed three real defect classes, but the pattern (docblock and type-rewriting rules are where the bugs live) suggests we should keep the highest-opinion rules on a watch list and review their diffs rather than auto-merging them.
How can I help you explore Laravel packages today?