| name | acc-psr-coding-style-knowledge |
| description | PSR-1 and PSR-12 coding standards knowledge base for PHP 8.5 projects. Provides quick reference for basic coding standard and extended coding style with detection patterns, examples, and antipattern identification. Use for code style audits and compliance reviews. |
PSR Coding Style Knowledge (PSR-1, PSR-12)
Quick Reference
| Standard | Focus | Key Rules |
|---|
| PSR-1 | Basic Standard | Files, namespaces, class names |
| PSR-12 | Extended Style | Formatting, keywords, visibility |
PSR-1: Basic Coding Standard
1. Files
| Rule | Requirement |
|---|
| Tags | MUST use <?php or <?= only |
| Encoding | MUST be UTF-8 without BOM |
| Side Effects | Files SHOULD declare symbols OR execute logic, not both |
2. Namespaces and Classes
| Rule | Requirement |
|---|
| Namespaces | MUST follow PSR-4 autoloading |
| Class Names | MUST be StudlyCaps (PascalCase) |
| Constants | MUST be UPPER_CASE_WITH_UNDERSCORES |
| Methods | MUST be camelCase |
3. Side Effects Detection
<?php
namespace App;
ini_set('display_errors', '1');
class Logger { }
<?php
ini_set('display_errors', '1');
require 'vendor/autoload.php';
<?php
declare(strict_types=1);
namespace App;
final readonly class Logger { }
PSR-12: Extended Coding Style
1. General
| Rule | Requirement |
|---|
| PSR-1 | MUST follow PSR-1 |
| Indentation | MUST use 4 spaces (no tabs) |
| Line Length | SHOULD be ≤120 chars, MUST NOT hard wrap |
| Line Ending | MUST be Unix LF (\n) |
| Blank Line | MUST have one at end of file |
| Trailing Space | MUST NOT have trailing whitespace |
2. Files
<?php
declare(strict_types=1);
namespace Vendor\Package;
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use function Vendor\Package\{functionA, functionB, functionC};
use const Vendor\Package\{ConstantA, ConstantB, ConstantC};
final readonly class ClassName extends ParentClass implements
InterfaceA,
InterfaceB,
InterfaceC
{
}
3. Keywords and Types
| Rule | Requirement |
|---|
| Keywords | MUST be lowercase (true, false, null) |
| Type Declarations | MUST be lowercase (int, string, bool) |
| Short Forms | MUST use bool, int (not boolean, integer) |
4. Classes, Properties, Methods
<?php
declare(strict_types=1);
namespace App\Domain\Entity;
use App\Domain\ValueObject\Email;
use App\Domain\ValueObject\UserId;
final readonly class User
{
public function __construct(
private UserId $id,
private Email $email,
private string $name,
private bool $isActive = true,
) {
}
public function getId(): UserId
{
return $this->id;
}
public function activate(): self
{
return new self(
$this->id,
$this->email,
->name,
,
);
}
}
5. Control Structures
<?php
if ($expr1) {
} elseif ($expr2) {
} else {
}
switch ($expr) {
case 0:
echo 'First case';
break;
case 1:
echo 'Second case';
default:
echo 'Default case';
break;
}
$result = match ($expr) {
0 => 'First',
1, 2 => 'Second or third',
default => 'Other',
};
while ($expr) {
}
for ($i = 0; $i < 10; $i++) {
}
foreach ($iterable as => ) {
}
{
} (FirstThrowableType ) {
} (OtherThrowableType | AnotherThrowableType ) {
} {
}
6. Operators
<?php
$sum = $a + $b;
$concat = $string1 . $string2;
$result = $condition ? $valueIfTrue : $valueIfFalse;
$i++;
--$j;
$negated = !$bool;
$intValue = (int) $floatValue;
$stringValue = (string) $intValue;
7. Closures and Arrow Functions
<?php
$closure = function (int $arg1, int $arg2) use ($var1, $var2): int {
return $arg1 + $arg2 + $var1 + $var2;
};
$longClosure = function (
int $argument1,
string $argument2,
bool $argument3,
) use (
$staticVar1,
$staticVar2,
): bool {
};
$multiply = fn(int $a, int $b): int => $a * $b;
8. Anonymous Classes
<?php
$instance = new class extends ParentClass implements SomeInterface {
use SomeTrait;
public function __construct(
private readonly int $value,
) {
}
};
Detection Patterns
PSR-1 Violations
grep -rn "^[[:space:]]*\(echo\|print\|header\|session_start\|ini_set\)" --include="*.php" src/
grep -rn "^class [a-z]" --include="*.php" src/
grep -rn "^class [A-Z][a-z]*_" --include="*.php" src/
grep -rn "function [A-Z]" --include="*.php" src/
grep -rn "function [a-z]*_[a-z]" --include="*.php" src/
PSR-12 Violations
grep -rn $'\t' --include="*.php" src/
grep -rn "[[:space:]]$" --include="*.php" src/
grep -rn "boolean\|integer" --include="*.php" src/
grep -rn "\(if\|for\|foreach\|while\|switch\|catch\)(" --include="*.php" src/
grep -rn "^class.*{$" --include="*.php" src/
PHP_CodeSniffer Configuration
<?xml version="1.0"?>
<ruleset name="PSR-12">
<description>PSR-12 coding standard</description>
<rule ref="PSR12"/>
<file>src</file>
<file>tests</file>
<exclude-pattern>vendor/*</exclude-pattern>
<arg name="colors"/>
<arg value="sp"/>
</ruleset>
PHP-CS-Fixer Configuration
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = Finder::create()
->in([
__DIR__ . '/src',
__DIR__ . '/tests',
])
->name('*.php');
return (new Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'@PHP84Migration' => true,
'declare_strict_types' => true,
'final_class' => true,
'class_attributes_separation' => [
'elements' => ['method' => 'one'],
],
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'function', 'const'],
],
'no_unused_imports' => true,
'trailing_comma_in_multiline' => [
'elements' => ['arguments', , ],
],
])
->();
Antipatterns
| Violation | PSR | Severity | Fix |
|---|
| Mixed declarations and side effects | PSR-1 | CRITICAL | Separate into bootstrap file |
| snake_case class names | PSR-1 | CRITICAL | Rename to StudlyCaps |
| Tabs for indentation | PSR-12 | WARNING | Convert to 4 spaces |
| Boolean/integer type hints | PSR-12 | WARNING | Use bool/int |
| Missing strict_types | - | WARNING | Add declaration |
| Opening brace on same line | PSR-12 | INFO | Move to next line |
| Trailing whitespace | PSR-12 | INFO | Remove whitespace |
Integration with DDD
Domain Layer
<?php
declare(strict_types=1);
namespace App\Domain\User\ValueObject;
final readonly class Email
{
private function __construct(
private string $value,
) {
}
public static function fromString(string $email): self
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidEmailException($email);
}
return new self($email);
}
public function toString(): string
{
return $this->value;
}
}
Application Layer
<?php
declare(strict_types=1);
namespace App\Application\User\UseCase;
use App\Application\User\Command\CreateUserCommand;
use App\Domain\User\Entity\User;
use App\Domain\User\Repository\UserRepositoryInterface;
final readonly class CreateUserHandler
{
public function __construct(
private UserRepositoryInterface $userRepository,
) {
}
public function __invoke(CreateUserCommand $command): void
{
$user = User::create(
$command->email,
$command->name,
);
$this->userRepository->save($user);
}
}
See Also
references/psr-1-basic.md - Full PSR-1 specification
references/psr-12-extended.md - Full PSR-12 specification
references/detection-patterns.md - Comprehensive detection patterns
references/antipatterns.md - Common violations with fixes
assets/report-template.md - Compliance report template