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

Attributes #[] Replacing Docblock Annotations

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

Closest to 'default linter catches the common case' (d3). PHPStan and Psalm (listed in detection_hints.tools) will flag missing #[Attribute] markers on custom attribute classes and usage in incompatible PHP versions. The syntax error from using #[] on PHP < 8.0 is caught at runtime/compile time immediately, pulling the score down slightly from d5.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says to migrate framework DocBlock annotations to native #[] attributes and add #[Attribute] markers to custom attribute classes. This is not a single-line patch — it requires touching every annotated class/method across potentially multiple files, updating or replacing annotation-reader libraries, and verifying Reflection-based reading. It stays at e5 rather than e7 because it's typically scoped to annotation usage patterns rather than truly cross-cutting architectural change.

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

Closest to 'localised tax' (b3). The applies_to covers web, cli, and queue-worker contexts broadly, but attribute usage is localised to classes/methods that carry metadata. Once migrated, the ongoing burden is low — future maintainers work with standard PHP syntax rather than fragile string-parsed DocBlocks. The choice doesn't reshape the entire codebase architecture.

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

Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly states that developers confuse DocBlock annotations (string-parsed via Reflection::getDocComment() + regex) with native PHP attributes (first-class structures). The common mistake of using attributes without reading them via Reflection — expecting them to have automatic runtime effect — reinforces this as a well-documented but non-obvious gotcha. Not t7 because once understood, the distinction is clear and consistent.

About DEBT scoring →

TL;DR

PHP 8.0 native attributes (#[Route('/home')]) replace fragile DocBlock @annotations — they're syntactically valid, parseable without reflection hacks, and supported by IDEs and static analysis.

Explanation

PHP 8.0 attributes: #[Attribute] on the attribute class, #[Route('/home')] on the target. Read with Reflection: (new ReflectionClass($obj))->getAttributes(Route::class). Benefits over DocBlocks: syntactically valid PHP (checked at parse time), no regex parsing, IDE completion, static analysis support, can be classes with validation. Built-in attributes: #[Override] (8.3), #[AllowDynamicProperties] (8.2), #[Deprecated] (8.4), #[ReturnTypeWillChange], #[SensitiveParameter] (8.2). Frameworks (Symfony, Laravel) have migrated from DocBlock annotations to native attributes.

Common Misconception

DocBlock annotations and PHP attributes are parsed the same way — DocBlocks are strings read with Reflection::getDocComment() + regex. Attributes are first-class PHP structures.

Why It Matters

Native attributes replace fragile string parsing with proper PHP syntax — eliminating annotation parsing bugs and enabling IDE autocompletion on metadata.

Common Mistakes

  • Using #[] syntax in PHP < 8.0 — fatal syntax error.
  • Not declaring the #[Attribute] marker on custom attribute classes.
  • Using attributes without reading them via Reflection — they have no effect at runtime on their own.

Code Examples

✗ Vulnerable
/**
 * @Route('/home', methods={'GET'})
 * @IsGranted('ROLE_USER')
 */
class HomeController {} // Parsed with fragile regex
✓ Fixed
#[Route('/home', methods: ['GET'])]
#[IsGranted('ROLE_USER')]
class HomeController {}

// Reading attributes:
$attrs = (new \ReflectionClass(HomeController::class))
    ->getAttributes(Route::class);
foreach ($attrs as $attr) {
    $route = $attr->newInstance();
}

Added 23 Mar 2026
Views 46
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 2 pings T 0 pings F 0 pings S 0 pings S 3 pings M 0 pings T 1 ping W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 10 ChatGPT 4 Unknown AI 4 Perplexity 4 Ahrefs 3 SEMrush 3 Scrapy 3 Google 2 Meta AI 2 Bing 2 Claude 1 Majestic 1 PetalBot 1
crawler 35 crawler_json 3 pre-tracking 2
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Medium
⚡ Quick Fix
Migrate framework DocBlock annotations to native #[] attributes. Add #[Attribute] to custom annotation classes. Use named args in complex attribute constructors.
📦 Applies To
PHP 8.0+ web cli queue-worker Symfony Laravel
🔗 Prerequisites
🔍 Detection Hints
#\[
Auto-detectable: ✗ No phpstan psalm
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class


✓ schema.org compliant