zicht/standards-php
Zicht's shared PHP coding standards package bundles PHP_CodeSniffer rules and static analysis configuration for consistent code style across projects. Install it with Composer and reference the ruleset in your phpcs.xml to enforce quality checks.
Architecture fit. zicht/standards-php is not a runtime Laravel package — it is a PHP_CodeSniffer (phpcs) ruleset distributed as a Composer package. That distinction drives the entire assessment: it has no service provider, no config publishing, no facades, no migrations, and zero footprint in production. It belongs in require-dev and in the CI/lint stage of the pipeline. For a Laravel codebase it competes directly with the default option (Laravel Pint), so the real architectural question is not "does it integrate" but "why this instead of Pint's Laravel preset". The legitimate answer is usually organizational: Zicht's standards encode house conventions (naming, docblocks, array syntax, Slevomat sniffs) that a generic PSR-12 preset doesn't, and reusing them keeps parity with sister projects or an external delivery partner.
Integration feasibility. Technically trivial. composer require --dev zicht/standards-php, then reference the standard in phpcs.xml. The one non-obvious dependency is how the standard gets registered with phpcs: either the package ships a dealerdirect/phpcodesniffer-composer-installer-compatible installed_paths declaration (in which case --standard=Zicht works out of the box) or it does not, and you must point at vendor/zicht/standards-php/... explicitly. That is a five-minute spike, but it should be confirmed before committing, because it determines the config surface and the IDE setup. Everything else — PhpStorm inspection profile, VS Code phpcs extension, GitHub Actions step — is standard phpcs plumbing.
Technical risk. Low blast radius, high supply-chain risk. The ruleset cannot break production; worst case it blocks CI. The real risks are:
squizlabs/php_codesniffer and slevomat/coding-standard. Slevomat's version constraints are notoriously narrow and frequently collide with other dev dependencies (PHPStan extensions, other rulesets). Expect at least one composer update negotiation.Key questions to resolve before adoption.
dealerdirect/phpcodesniffer-composer-installer, or must the path be hardcoded?Stack fit. Works in any Composer-managed PHP project, Laravel included. It slots in alongside PHPStan/Larastan and Pint as the style layer. Recommended position: phpcs (with this ruleset) as the sniff authority in CI; disable Pint's formatting if the rulesets disagree, or configure Pint's preset to psr12 only and let this package own the rest. Do not run both as auto-fixers.
Migration path. Do not flip CI to blocking on day one — a mature Laravel codebase will produce hundreds to thousands of violations and the resulting mega-commit destroys git blame.
"zicht/standards-php": "x.y.z") rather than ^.phpcs.xml that references the Zicht ruleset and explicitly exclude-patterns vendor/, storage/, bootstrap/cache/, and any legacy directories.phpcs --report=summary and --report=source to quantify violations by sniff. This tells you whether the gap is trivial (whitespace, import ordering) or semantic (naming, docblock contracts).phpcbf on app/ and tests/. Commit as a formatting-only commit and add it to .git-blame-ignore-revs.--warning mode, then flip to blocking once the baseline is clean. Optionally gate new code only, via a changed-files lint step.Compatibility. Verify against the PHP matrix we actually deploy (8.1/8.2/8.3). Because the ruleset transitively pins PHPCS, a PHP upgrade on the app and a PHP upgrade on the linter are coupled — note this in the upgrade runbook. If the package is stale, the fallback is to fork it or, cheaper, vendor the XML ruleset into tools/phpcs/Zicht/ in-repo and own it. A ruleset is a few hundred lines of XML; forking is a realistic and low-cost de-risking move.
Sequencing. (1) Timeboxed spike — install, register, run against the repo, measure. (2) Decision gate: adopt / extend-and-override / fork / reject in favor of Pint. (3) Formatting commit + blame-ignore. (4) CI warning mode. (5) CI blocking + pre-commit hook. (6) Document in CONTRIBUTING.md and wire the IDE. Total effort for a mid-size Laravel app: roughly 2–4 engineering days, dominated by the auto-fix commit and the dependency negotiation, not the integration itself.
Maintenance. The ongoing cost is low but non-zero and slightly open-ended because ownership sits outside the team. Pin the version; upgrade deliberately as a scheduled chore, not opportunistically. Keep the local phpcs.xml as a thin overlay that includes the Zicht ruleset and adds our exclusions — this preserves the ability to override a single sniff without forking and gives a clean exit ramp if the upstream goes dark. Budget a quarterly check on upstream activity.
Support. There is no meaningful community support channel: no stars, no dependents, no apparent issue traffic. Treat support as "best effort, possibly none." If Zicht is a delivery partner or vendor, route questions through that relationship; if not, plan on self-support. That is acceptable for a linting ruleset and unacceptable for anything touching runtime — which this does not.
Scaling. The ruleset itself is O(1); cost scales linearly with lines of code and files. On a large codebase, phpcs is slow in single-threaded mode — use phpcs with parallelism (--parallel), or lint only changed files in PRs and run the full pass nightly. In a monorepo, give each package its own phpcs.xml inheriting from a root overlay so standards stay consistent without one giant scan.
Failure modes to watch.
composer install (usually an installed_paths ordering issue) → CI fails confusingly with "standard not found". Pin the composer-installer plugin explicitly.phpcs.xml rather than its own settings.tools/ composer.json if this becomes frequent.Ramp-up. Low. Any PHP developer who has seen phpcs understands the workflow; the only novelty is the house-specific sniffs, which need a short README section with examples of "what it wants." Teams already on Pint will need a one-time explanation of why a second tool exists and which one wins — that confusion is the most likely source of day-to-day friction, and it is a documentation problem, not a technical one.
Recommendation. Adopt only if the Zicht standards are an actual organizational requirement (partner parity, shared codebase conventions). If the goal is simply "good Laravel style," Laravel Pint is the lower-risk default: maintained, first-party-adjacent, zero registration ambiguity, and no stale dependency pins. If adopted, pin exactly, wrap in a local overlay, measure before enforcing, and keep the fork option warm.
How can I help you explore Laravel packages today?