PSR-12 Coding Standard
debt(d3/e1/b2/t3)
Closest to 'default linter catches the common case' (d3), php-cs-fixer and phpcs with PSR-12 ruleset catch violations automatically and are standard in PHP toolchains.
Closest to 'one-line patch or single-call swap' (e1), quick_fix is to add php-cs-fixer with PSR-12 ruleset which auto-fixes violations on save — essentially a tool config addition.
Closest to 'localised tax' (b3) but lighter, scored b2 — applies across all PHP contexts but is a near-universal community standard with tooling support, so imposes minimal ongoing weight beyond CI enforcement.
Closest to 'minor surprise' (t3), misconception is that PSR-12 covers all style decisions when it deliberately omits trailing commas, quote style, etc. — a documented gap teams discover but it's not catastrophic.
Also Known As
TL;DR
Explanation
PSR-12 (accepted 2019) extends and replaces PSR-2, building on PSR-1. It specifies: files must use Unix LF line endings and end with a blank line; 4-space indentation; lines up to 120 characters (soft limit 80); one blank line between use declarations and class body; opening braces for classes and methods on their own line; no space before parentheses in control structures. Most PHP projects enforce PSR-12 via PHP_CodeSniffer or PHP-CS-Fixer in CI pipelines.
Common Misconception
Why It Matters
Common Mistakes
- Not using an automated formatter (PHP CS Fixer) — manual PSR-12 compliance is inconsistent.
- Braces on the same line for class and function declarations — PSR-12 requires them on the next line.
- Missing blank lines between method declarations.
- Not enforcing PSR-12 in CI — the standard degrades without automated enforcement.
Code Examples
<?php
class Foo{
public function bar($x,$y){
if($x){return $y;}
return null;
}}
// PSR-12 compliant:
class Foo
{
public function bar(int $x, int $y): ?int
{
if ($x) {
return $y;
}
return null;
}
}
<?php
declare(strict_types=1);
namespace App\Domain\Order;
use App\Domain\User\User;
use DateTimeImmutable;
class Order
{
public function __construct(
private readonly int $id,
private readonly User $customer,
private readonly DateTimeImmutable $placedAt,
) {
}
public function getId(): int
{
return $this->id;
}
}