ACTIVATE whenever writing or modifying PHP code in src/, creating controllers, services, repositories, specifications, or any production PHP class. ACTIVATE for code review, formatting questions, or 'coding standards'. Covers: project-specific spacing rules around control structures, early return patterns, no empty() policy, constructor parameter ordering, nowdoc conventions. These rules go BEYOND PSR-12/PER. DO NOT use for: test code conventions (see php-test-conventions), SQL formatting (see php-sql-conventions).
From phpnpx claudepluginhub fabiensalles/claude-marketplace --plugin phpThis skill uses the workspace's default tool permissions.
references/code-examples.mdGuides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Designs, audits, and improves analytics tracking systems using Signal Quality Index for reliable, decision-ready data in marketing, product, and growth.
Enforces A/B test setup with gates for hypothesis locking, metrics definition, sample size calculation, assumptions checks, and execution readiness before implementation.
All code complies with PSR-12 and PER Coding Style. The rules below are project-specific conventions that go beyond these standards -- this is what matters here.
IMPORTANT: Always add blank lines before and after control structures (foreach, for, while, if, switch) when they are not at the start or end of a block.
This rule is not in PSR-12/PER (which only states blank lines "MAY be added"). In this project, they are required.
Exception: No blank line needed when the control structure is at the start or end of a method/block.
When applying spacing rules around control structures, read
references/code-examples.mdfor complete foreach, if, and exception examples.
Always use early return to handle edge cases and invalid conditions first. This reduces nesting and improves readability.
return is preceded by other statements in a block, add a blank lineWhen refactoring nested conditions to early returns, read
references/code-examples.mdfor before/after examples and blank line rules.
continue in a loop is the equivalent of early return in a function. Use continue only when the exit condition is simple and the main processing is more complex.
When both branches have comparable complexity, prefer a classic if/else for readability.
Note: Add a blank line before
continue(andreturn,break,throw) when preceded by other statements in the block.
When deciding between continue and if/else in loops, read
references/code-examples.mdfor side-by-side comparisons.
Use the nullsafe operator ?-> to avoid nested null checks.
When using match with nullable input, add null as a case.
When flattening nested null checks, read
references/code-examples.mdfor nullsafe operator and match patterns.
NEVER use the empty() function. Use explicit comparisons instead.
The
empty()function has unpredictable behavior with different types and hides potential bugs.
| Type | Correct | Avoid |
|---|---|---|
| Arrays | $array === [] | empty($array) |
| Strings | $string === '' | empty($string) |
| Null | $value === null | empty($value) |
In constructors, mandatory parameters come first, then optional ones. Within each group, promoted properties come before simple parameters:
public/private/protected, required)public/private/protected, nullable)When ordering constructor parameters, read
references/code-examples.mdfor correct and incorrect examples.
Reference: PER Coding Style - Section 10
A nowdoc SHOULD be used wherever possible. Heredoc MAY be used only when a nowdoc does not satisfy requirements.
Indentation rules:
When writing heredoc/nowdoc blocks, read
references/code-examples.mdfor PER-compliant and non-compliant examples.
| Rule | Example |
|---|---|
| Early return | if (invalid) { return; } then main logic |
| If continue in loops | Only when simple condition vs complex main logic |
| If/else in loops | When both branches have comparable complexity |
| Blank line before flow control | $x = 1; then blank then return; / continue; / break; |
| Blank line before control structure | $x = 1; then blank then foreach (...) |
| Blank line after control structure | } then blank then $y = 2; |
| Exception: start of block | No blank line needed |
| Exception: end of block | No blank line needed |
| Nullsafe for nested null checks | $a?->b?->c instead of nested if |
No empty() function | $array === [] instead of empty($array) |
| Prefer nowdoc | <<<'SQL' instead of <<<SQL |
| Heredoc/nowdoc indentation | Content +1 level, closing same as content |