← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Attributes / Annotations (PHP 8.0)

php PHP 8.0+ Intermediate
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5), Rector and PHPStan (per detection_hints.tools) can flag missing #[Attribute] on attribute classes, missing target flags, and docblock annotations that should be migrated — but a default editor/linter won't catch misuse.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3), quick_fix is replacing @annotation docblocks with #[Attribute] syntax — a mechanical pattern swap, often Rector-automatable, but typically touches multiple annotated classes rather than a single line.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3), attributes apply within the metadata layer (routing, ORM, validation) of a PHP 8+ codebase; they are a localised idiom rather than a system-shaping choice, though they touch multiple contexts (web/cli/queue).

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5), misconception field states devs assume attributes have runtime cost like docblock annotations — they're actually lazy via Reflection with zero cost unless read. Plus the common mistake of forgetting #[Attribute] on the attribute class itself is a documented gotcha.

About DEBT scoring →

Also Known As

PHP attributes #[Attribute] PHP 8 annotations

TL;DR

Native structured metadata attached to classes, methods, properties, and parameters using #[AttributeName] syntax.

Explanation

PHP 8.0 attributes replace docblock-based annotations (used by PHPDoc, Doctrine, Symfony) with a first-class language feature. Attributes are declared with #[Attribute] on a class and applied with #[MyAttribute(args)] to target declarations. They are read at runtime via the Reflection API, making them suitable for routing, validation, serialisation, ORM mappings, and dependency injection metadata. Unlike docblocks, attributes are parsed by PHP itself, so syntax errors are caught at compile time.

Common Misconception

PHP attributes are processed at runtime like docblock annotations. Attributes are resolved lazily via Reflection — they have zero runtime cost unless explicitly read. Docblock annotations require string parsing every time; attributes are part of the compiled opcode.

Why It Matters

PHP 8 Attributes provide native structured metadata on classes, methods, and properties — replacing docblock annotations with something that is parseable, type-safe, and IDE-verifiable.

Common Mistakes

  • Defining an Attribute class without #[Attribute] itself — the class is not recognised as an attribute.
  • Not specifying the Attribute target flags — an attribute intended only for methods can accidentally be applied to classes.
  • Accessing attribute data with manual regex parsing of docblocks instead of using ReflectionClass->getAttributes().
  • Using attributes for runtime behaviour without understanding they require Reflection to read — they add no runtime behaviour themselves.

Code Examples

✗ Vulnerable
// Attribute class missing the #[Attribute] marker:
class Route { // Not recognised as an attribute
    public function __construct(public string $path) {}
}

#[Route('/users')] // Silent no-op
class UserController {}
✓ Fixed
// Define a custom attribute
#[Attribute(Attribute::TARGET_METHOD)]
class Route {
    public function __construct(
        public readonly string $path,
        public readonly string $method = 'GET',
    ) {}
}

// Apply it
class UserController {
    #[Route('/users', 'GET')]
    public function index(): array { return []; }

    #[Route('/users', 'POST')]
    public function store(array $data): User { ... }
}

// Read it via Reflection
$ref   = new ReflectionClass(UserController::class);
foreach ($ref->getMethods() as $method) {
    $attrs = $method->getAttributes(Route::class);
    foreach ($attrs as $attr) {
        $route = $attr->newInstance(); // Route object
        echo "{$route->method} {$route->path}\n";
    }
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 30
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 4 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Amazonbot 9 Perplexity 8 Google 2 Ahrefs 2 ChatGPT 2 SEMrush 1
crawler 22 crawler_json 2
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Replace @annotation docblock comments with #[Attribute] native attributes — they are parsed by PHP itself with zero reflection overhead for reading
📦 Applies To
PHP 8.0+ web cli queue-worker symfony doctrine
🔗 Prerequisites
🔍 Detection Hints
@Route @ORM\Entity @Assert docblock annotations that could be replaced with PHP 8 native attributes
Auto-detectable: ✓ Yes rector phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class

✓ schema.org compliant