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

Phpcs Psr4 Sniff Laravel Package

suin/phpcs-psr4-sniff

suin/phpcs-psr4-sniff is a PHP_CodeSniffer sniff that validates PSR-4 autoloading rules, flagging namespace, directory, and filename mismatches so Composer autoloading stays reliable in Laravel and other PHP projects.

Deep Wiki
Context7

Getting Started

suin/phpcs-psr4-sniff is a PHP_CodeSniffer standard that compares the class name and namespace declared in a file against the PSR-4 path it lives at, using your project's autoload mapping. It catches the class of bugs that Composer silently tolerates: a file src/Order/CreateOrder.php that declares namespace App\Orders; or class CreateOrderHandler. Composer will simply fail to autoload it at runtime; this sniff fails the build instead.

Install it as a dev dependency:

composer require --dev suin/phpcs-psr4-sniff

If you don't already use dealerdirect/phpcodesniffer-composer-installer, register the standard manually (PHPCS 3.x):

vendor/bin/phpcs --config-set installed_paths vendor/suin/phpcs-psr4-sniff
vendor/bin/phpcs -i          # confirm the "PSR4" standard is listed

Then run it against your source tree from the project root (it needs to find composer.json):

vendor/bin/phpcs --standard=PSR4 src

Where to look first:

  • README.md — the canonical run command and any runtime config.
  • The bundled ruleset (typically PSR4/ruleset.xml) — tells you the sniff's registered name and where it will apply.
  • The sniff class itself — small enough to read end-to-end if you need to understand exactly what it compares.

First use case: run it against a directory you've just reorganized. Deliberately rename a class or change a namespace prefix in one file and confirm the sniff reports it. That one-minute experiment tells you whether it's wired up correctly before you add it to CI.

Implementation Patterns

Put it in a project ruleset rather than invoking it ad hoc. This is the pattern that actually survives:

<?xml version="1.0"?>
<ruleset name="MyProject">
    <file>app</file>
    <file>src</file>

    <exclude-pattern>*/vendor/*</exclude-pattern>
    <exclude-pattern>*/storage/*</exclude-pattern>
    <exclude-pattern>*/database/migrations/*</exclude-pattern>
    <exclude-pattern>*/tests/Fixtures/*</exclude-pattern>

    <rule ref="PSR4"/>
    <rule ref="PSR12"/>
</ruleset>

Then vendor/bin/phpcs picks it up automatically, and editors/CI share one definition.

In a Laravel app, app/ maps to App\, so the standard works out of the box — but scope the ruleset carefully. Exclude config/, routes/, database/migrations/, resources/, and bootstrap/cache/, where files are intentionally not one-class-per-file PSR-4 artifacts. If you exclude too little you'll drown in false positives and disable the sniff within a week.

Chain it into Composer scripts so it runs wherever your tests run:

"scripts": {
  "lint:psr4": "phpcs --standard=PSR4 app src",
  "check": ["@lint:psr4", "@test"]
}

Run it in CI as a distinct step from your style checks. A PSR-4 violation is a correctness bug (the class won't autoload), not a formatting preference, so treat its failure differently from a PSR-12 failure. Keeping it separate also makes it easier to adopt: you can allow style drift while blocking autoload breakage.

Adopt gradually on legacy code. If the codebase has hundreds of mismatches, start with a report-only job (phpcs ... || true) or only target the directories that are already clean. New code goes through the gate immediately; old code gets cleaned up opportunistically when files are touched.

Check only changed files in pre-commit hooks. Full-tree runs get slow on large repos; feed git diff --name-only --diff-filter=ACM -- '*.php' into phpcs --stdin-path=... (or xargs) for the hook, and reserve the full scan for CI.

Pair it with composer dump-autoload --optimize --strict-psr. Since Composer 2.x, --strict-psr also reports PSR-4 path/namespace mismatches; running both gives you coverage from the Composer side and from the editor/CI side.

Gotchas and Tips

  • Effectively unmaintained. Last release was mid-2021 and the repo is read-only. Expect it to target PHPCS 3.x. Do not let composer update pull in PHP_CodeSniffer 4.x without testing — the internal APIs changed and this sniff will likely break. Pin squizlabs/php_codesniffer to ^3.x for as long as you depend on it.
  • Nothing after PHP 8.0 is safely supported. Enums, readonly properties, and newer token types may confuse the sniff. If your codebase has enums in PSR-4 paths, verify behavior on a sample file before trusting the results.
  • It reads composer.json to know the namespace-to-directory mapping. Run it from the directory containing the correct composer.json. In a monorepo, running from the root may resolve the wrong autoload block — invoke per package, or from a working directory where the mapping is unambiguous.
  • Multiple autoload roots are a common blind spot. A package with "App\\": "app/" and "App\\Tests\\": "tests/" needs both to be discovered; if the sniff only recognizes one, you'll get spurious failures in tests/.
  • Case sensitivity bites on macOS. PSR-4 is case-sensitive, but APFS is not. A file createOrder.php declaring CreateOrder will pass locally and fail on Linux CI (or fail to autoload in production). Run the sniff in a Linux CI job — that's where it earns its keep.
  • Anonymous classes and files with multiple classes are the main sources of false positives. Test files and fixtures often stack helper classes in one file; exclude them explicitly rather than trying to make the sniff smarter.
  • Distinguish PHPCS exit codes. 1 means violations found; 2 means a configuration/execution error (e.g., standard not found). Treating 2 as "just violations" is how people ship with a silently disabled sniff.
  • Debug with -s. vendor/bin/phpcs --standard=PSR4 -s src prints the sniff code on each message, which is what you need if you're excluding individual sniffs or writing phpcs:ignore comments.
  • phpcs:ignore comments are the escape hatch, but use them sparingly and with the code name (// phpcs:ignore PSR4.…). A blanket ignore is a future autoload bug.
  • It validates declarations, not loading. A clean run does not prove your class is reachable — a class can match its path and still be in an unregistered autoload root. Combine with composer dump-autoload --strict-psr and a smoke test that references the class.
  • Extension points are minimal by design. This is a single small sniff, not a framework. If you need custom rules (e.g., forbidding multiple classes per file), copy the sniff into your own internal coding standard and evolve it there — do not expect upstream changes.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings