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

readonly Properties (PHP 8.1)

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

Closest to 'specialist tool catches it' (d5). The term's detection_hints lists rector and phpstan as tools, both specialist static analysis tools. The code_pattern suggests detecting old-style private property + getter patterns requires a tool like Rector or PHPStan to flag; it won't be caught by a compiler error or default linter, but these specialist tools can identify missing readonly opportunities or misuse (e.g. setting after construction throws a runtime Error, not a compile-time one in most cases).

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix states 'Add readonly to immutable properties. Combine with constructor promotion for concise value objects. Use readonly class (PHP 8.2) for fully immutable types.' This is a small, mechanical refactor — replacing private property + getter patterns with readonly — confined to one class at a time, not a cross-cutting architectural change.

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

Closest to 'localised tax' (b3). readonly is a property-level modifier. Its applies_to spans web, cli, and queue-worker contexts broadly, but the structural commitment is per-class — once applied, a readonly property is immutable by design. The burden is that value objects using readonly need a with() method pattern (pre-8.3) or __clone() (8.3+) for modifications, but this is localised to the class itself rather than spreading across the codebase.

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

Closest to 'notable trap' (t5). The misconception field explicitly states: 'readonly prevents cloning with modifications — PHP 8.3 allows modifying readonly properties in __clone(). Before 8.3, use a with() method that returns a new instance.' This is a documented gotcha that most developers encounter when trying to clone or mutate readonly value objects, and the version-dependent behaviour (pre-8.3 vs 8.3+) adds another layer of surprise. The common_mistakes also include the type declaration requirement and missing readonly class syntax.

About DEBT scoring →

TL;DR

PHP 8.1 readonly properties can only be written once (in the constructor) — enforcing immutability without verbose accessor boilerplate.

Explanation

public readonly string $name; cannot be written after initialization. Writing a second time throws Error. Cannot be unset. Must be typed. Cannot have a default value in declaration (except via constructor promotion). Combined with constructor promotion: public function __construct(public readonly string $name) — declare + promote + make readonly in one line. PHP 8.2 readonly classes: mark the entire class and all promoted properties are readonly. PHP 8.3 allows readonly property modification in __clone() for clone-with patterns. Use readonly for value objects, DTOs, request objects.

Common Misconception

readonly prevents cloning with modifications — PHP 8.3 allows modifying readonly properties in __clone(). Before 8.3, use a with() method that returns a new instance.

Why It Matters

readonly eliminates the need for private property + public getter for immutable data — reducing boilerplate and enforcing value object immutability by the language.

Common Mistakes

  • Trying to set readonly property after construction — throws Error.
  • Forgetting readonly requires a type declaration.
  • Not using readonly class (8.2) when all properties should be immutable.

Code Examples

✗ Vulnerable
class Money {
    private int $amount;
    private string $currency;

    public function getAmount(): int { return $this->amount; }
    public function getCurrency(): string { return $this->currency; }
}
✓ Fixed
// PHP 8.1 — readonly + constructor promotion:
class Money {
    public function __construct(
        public readonly int $amount,
        public readonly string $currency,
    ) {}
}

// PHP 8.2 — readonly class:
readonly class Money {
    public function __construct(
        public int $amount,
        public string $currency,
    ) {}
}

Added 23 Mar 2026
Views 51
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 5 pings S 3 pings S 0 pings M 2 pings T 0 pings W 0 pings T 1 ping F 0 pings 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
Scrapy 9 Amazonbot 7 ChatGPT 4 Unknown AI 3 Perplexity 3 Google 3 Ahrefs 3 Claude 2 Bing 1 Meta AI 1 PetalBot 1
crawler 32 crawler_json 3 pre-tracking 2
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Low
⚡ Quick Fix
Add readonly to immutable properties. Combine with constructor promotion for concise value objects. Use readonly class (PHP 8.2) for fully immutable types.
📦 Applies To
PHP 8.1+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
private \$[a-z].*getters
Auto-detectable: ✗ No rector phpstan
🤖 AI Agent
Confidence: Low False Positives: High ✓ Auto-fixable Fix: Medium Context: Class


✓ schema.org compliant