Its focus is language features that LLMs frequently get wrong or write in a pre-8.0 style — most notably using docblock annotations (@Route, @ORM\Column) instead of native #[Attribute] syntax, which is the #1 mistake this skill exists to prevent.
Do NOT use this skill for coding style, PSR compliance, or autoloading — that is php-standards. Do NOT use it for Laravel-specific syntax conventions — that lives in the Laravel plugin.
Modern PHP Language (8.1 → 8.5)Agent Workflow (MANDATORY)
Before writing PHP, spawn 3 agents in parallel, one Agent call each with a name:
- fuse-ai-pilot:explore-codebase - Detect the project's minimum PHP version (
composer.jsonrequire.php, CI matrix) - fuse-ai-pilot:research-expert - Verify a feature's version + syntax on php.net before using it
- mcp__context7__query-docs - Cross-check idiomatic usage
After writing, run fuse-ai-pilot:sniper for validation.
Overview
| Feature | Since | Use it for |
|---|---|---|
| Enums (backed + methods/interfaces) | 8.1 | Closed sets of values with behavior |
First-class callable syntax f(...) |
8.1 | Passing callables without strings |
| readonly properties / classes | 8.1 / 8.2 | Immutable value objects / DTOs |
#[\Override] |
8.3 | Fail-fast on broken inheritance |
Property hooks get/set |
8.4 | Computed/validated properties, no getter/setter boilerplate |
Asymmetric visibility public private(set) |
8.4 (static: 8.5) | Public read, restricted write |
Lazy objects newLazyGhost() |
8.4 | Deferred initialization in DI containers |
Pipe operator |> |
8.5 | Left-to-right data transformation chains |
clone() function + $withProperties |
8.5 | Immutable "with" updates, incl. readonly |
#[\NoDiscard] |
8.5 | Enforce return-value consumption |
Critical Rules
- Attributes, never docblock annotations - Native
#[Attribute]replaces@annotationdocblocks for routing, ORM, DI, validation. This is the #1 LLM mistake — see attributes-over-docblocks.md. - Check the target PHP version first - Never emit 8.5 syntax on an 8.1 project. Read
composer.jsonrequire.phpbefore choosing a feature. - Prefer enums over class constants for closed value sets — they carry type safety and methods.
- Prefer
readonly+ property hooks over hand-written getters/setters — less boilerplate, enforced immutability. declare(strict_types=1);at the top of every file.
Architecture
src/
├── Enum/
│ └── Status.php # backed enum + interface + methods
├── ValueObject/
│ └── Money.php # readonly class, clone() with $withProperties
└── Model/
└── User.php # property hooks, asymmetric visibility
→ See modern-class.md for complete working code
Reference Guide
Concepts
| Topic | Reference | When to Consult |
|---|---|---|
| PHP 8.5 features | php-85-features.md | Pipe operator, clone(), #[\NoDiscard], static aviz |
| PHP 8.4 features | php-84-features.md | Property hooks, aviz, lazy objects, #[\Deprecated] |
| 8.1–8.3 baseline | php-81-83-baseline.md | Enums, readonly, fibers, #[\Override] |
| Attributes vs docblocks | attributes-over-docblocks.md | Any metadata: routing, ORM, DI, validation |
Templates
| Template | When to Use |
|---|---|
| modern-class.md | Writing a new class the modern way |
Best Practices
DO
- Read
require.phpbefore picking a feature version - Use enums with interfaces + methods for stateful value sets
- Use property hooks for validation/computation instead of magic
__get - Use the pipe operator to flatten nested calls (8.5+)
DON'T
- Write
@Route/@ORM\Columndocblock annotations — use attributes - Emit 8.4/8.5 syntax without confirming the project supports it
- Hand-roll getters/setters when hooks or
readonlyfit - Guess a feature's version — verify on php.net