lumnd / plato-coding-standard
The PHP_CodeSniffer standard behind PlatoPHP: PSR-12 minus the naming and brace conventions it does not follow, plus the sniff that enforces them
Package info
github.com/lumnd/plato-coding-standard
Type:phpcodesniffer-standard
pkg:composer/lumnd/plato-coding-standard
Requires
- php: ^8.0
- dealerdirect/phpcodesniffer-composer-installer: ^1.0
- squizlabs/php_codesniffer: ^3.11
This package is not auto-updated.
Last update: 2026-08-07 04:25:37 UTC
README
The PHP_CodeSniffer standard behind PlatoPHP: PSR-12 minus the naming and brace conventions it deliberately does not follow, plus the sniff that enforces them.
Excluding a PSR-12 sniff only makes both spellings legal. A tree that excludes
Squiz.Classes.ValidClassName does not require snake_case — it stops having an opinion, and the two
styles drift apart inside one repository with nothing to say so. This package is both halves: the
exclusions, and ProjectConventionsSniff, which rejects the PSR-12 spelling in their place.
It exists because the exclusions were pasted into three repositories and drifted. One copy was
missing Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace and still errored on
wrapped signatures; one carried a bug in the sniff that the others had already fixed; one shipped a
standard named after the wrong project. A convention with three copies has no authority.
Requirements
| PHP | 8.0+ |
| PHP_CodeSniffer | ^3.11 |
Install
composer require --dev lumnd/plato-coding-standard
This package's type is phpcodesniffer-standard, which is what
dealerdirect/phpcodesniffer-composer-installer scans installed packages for. It writes this
directory into phpcs's installed_paths, and that is what lets a consumer name the standard instead
of spelling out a path into vendor/. The plugin is a hard requirement rather than a suggestion:
without it the standard installs but never registers, and the ruleset fails to resolve the name with
an error that does not say why.
Composer will not run a plugin a project has not allowed, so the consuming composer.json needs:
{
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
Use
A consumer's phpcs.xml keeps what is genuinely its own — which directories to check, which
generated output to skip — and refs the standard by name:
<?xml version="1.0"?> <ruleset name="MyProject"> <file>src</file> <exclude-pattern>src/generated/*</exclude-pattern> <rule ref="PlatoPHP"/> </ruleset>
Everything else — the PSR-12 base, the exclusions, the 120 column soft limit, Allman braces for
functions and closures, ignore_warnings_on_exit — comes with the name.
What it enforces
| Code | Rule |
|---|---|
ClassName |
Classes, interfaces, traits and enums are lowercase snake_case |
FunctionName |
Functions and methods are lowercase snake_case |
MethodVisibilityPrefix |
private / protected methods start with _; public ones do not |
PropertyVisibilityPrefix |
The same for properties |
SpaceAfterOpenParenthesis SpaceBeforeCloseParenthesis |
One space inside control parentheses: if ( $ready ) |
ControlBraceLine |
A control structure's opening brace is on the line after the signature |
ContinuationLine |
else, catch, finally and do-while start on a new line, not } else |
All codes are prefixed PlatoPHP.Style.ProjectConventions.
Zero errors is the gate. The 120 column limit is a warning, which PSR-12 requires it to be, and
ignore_warnings_on_exit keeps it out of the exit code.
What phpcbf fixes, and what it will not
The whitespace rules are fixable — composer style:fix rewrites if($x){ into the convention,
including moving else and catch onto their own lines. Two cases are reported without a fix on
purpose, because closing the gap would change more than formatting:
- A condition wrapped over several lines. Turning the newline into a space would join two lines rather than insert one space.
- A comment between the signature and the brace. It belongs on one side of the break and the sniff does not know which.
The naming rules are never fixable. Renaming a method means finding its callers, which is not something a formatter should attempt.
Exceptions
Magic methods are exempt from both naming rules. __toString, __callStatic and __debugInfo
are camelCase and __construct is public while starting with an underscore — the engine owns those
spellings, so they are not a project's to choose. The sniff carries PHP's list and skips it.
A name a third party dictates is not relaxed, it is suppressed where it happens. A class
implementing PSR-16 must provide getMultiple(); renaming it would mean not implementing the
interface. Mark that class rather than widening the rule for everybody:
// phpcs:disable PlatoPHP.Style.ProjectConventions.FunctionName -- PSR-16 owns these names. public function getMultiple(iterable $keys, mixed $default = null): iterable // phpcs:enable PlatoPHP.Style.ProjectConventions.FunctionName
ProjectConventionsSniff does the same to itself: PHPCS's loader requires a StudlyCaps class name
ending in Sniff, so the file carries a one-line phpcs:ignore for its own ClassName rule.
Tests
composer test
Runs the standard over tests/fixtures and asserts what fires, what does not, what phpcbf rewrites,
that a second fix run changes nothing, and that the two unfixable cases come back byte-identical.
There is no test framework: a coding standard is a dependency of everybody else's test setup, and
giving it one of its own buys a version conflict for nothing.
composer style
Checks this package against the standard it ships.
License
MIT.