PHP_CodeSniffer

LanguagePHP
Kindtool
Readiness🟡
Detector conformance🟡
Checked2026-09-08, version 4.0.4

PHP_CodeSniffer tokenises PHP and runs sniffs over the token stream, reporting violations of a coding standard and fixing many of them with phpcbf. It is usually the style gate in a pipeline, but a sniff can detect any token-level pattern, so it is a serviceable host for a bespoke defence.

How it is conformant

Clause 4.1 is met: a project defines a standard with a ruleset.xml and a Sniffs directory, and each sniff subscribes to tokens and reports through addError with a code of its own (coding standard tutorial). Clause 4.2 is met by the command line: --sniffs=Standard.Category.Sniff restricts a run to one sniff, and a file path restricts it to one file, so a red run against a fixture needs no test suite (advanced usage). Clauses 5.1 to 5.4 hold for the same reason: the run is local, takes a single file and prints its report to the terminal. Clause 7.1 is met because --ignore-annotations disables every phpcs:ignore and phpcs:disable comment, the ruleset can hard-code that flag with <arg name="ignore-annotations"/>, and the tokeniser exposes the annotations as their own tokens so a project sniff can detect them (advanced usage, annotated ruleset).

How it is not conformant

Clause 4.3 is the readiness gap and a failing MUST. The printed code is Standard.Category.Sniff.ErrorCode, and the tutorial states it is derived from the directory structure and class name, which is exactly what the clause forbids; only the final segment is the author’s to choose, and renaming the sniff file renames every reference. The code is also printed only with -s, which the ruleset can hard-code with <arg value="s"/> but the default output omits. Clauses 6.1 to 6.3 fail: nothing resolves a printed code to documentation, -e lists names without remedy text, and the bundled standards are documented on the wiki rather than on disk. Clause 7.2 fails because a note after -- on an ignore comment is optional rather than required (advanced usage). Clause 4.4 is not met, since addError requires a code but nothing checks that it is stable, and clause 6.4 was not verified.

Clause by clause

Document Clause Result Evidence
Detector 4.1 Yes Custom standard and sniffs, coding standard tutorial
Detector 4.2 Yes --sniffs plus a file path, advanced usage
Detector 4.3 Partial Code derived from path and class name; printed only with -s, advanced usage
Detector 4.4 No addError requires a code, but the code need not be stable
Detector 5.1 Yes phpcs runs locally
Detector 5.2 Yes phpcs /path/to/file
Detector 5.3 Yes Report prints to the terminal
Detector 5.4 Yes No CI-only mode
Detector 6.1 No No lookup keyed on the printed code
Detector 6.2 No Bundled standards documented on the wiki
Detector 6.3 No Same
Detector 6.4 Not verified No release gate over sniff documentation found
Detector 7.1 Yes --ignore-annotations disables inline routes; annotations are tokens a sniff can detect, advanced usage
Detector 7.2 No Reason after -- is optional, advanced usage

Notes for a practitioner

Put <arg value="s"/> in the ruleset so every finding carries its code, never rename a sniff once its code has been printed, and prove a new sniff with phpcs --sniffs=... fixture.php. Set --ignore-annotations in the ruleset or ban phpcs:ignore with a sniff of your own, and keep exclusions as ruleset <exclude-pattern> entries with a comment above each.