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

Lazy Objects (PHP 8.4)

PHP PHP 8.4+ Advanced
debt(d7/e3/b3/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The term's detection_hints.automated is 'no', and while the code pattern `newLazyGhost|newLazyProxy` can be searched for, misuse (using lazy objects for always-used services, or accessing uninitialized objects incorrectly) won't be caught by standard linters or SAST tools. Issues surface at runtime when performance isn't improved or when unexpected behaviour occurs.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix indicates using ReflectionClass::newLazyGhost() for deferred service initialisation. Fixing misuse typically involves changing DI container configuration or switching between ghost/proxy patterns — localized changes within service registration code, not cross-cutting refactors.

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

Closest to 'localised tax' (b3). Applies to web, cli, queue-worker contexts but lazy objects are typically isolated to DI container bootstrap logic. The choice affects service instantiation patterns but doesn't impose load-bearing constraints across the entire codebase — it's contained within infrastructure code.

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

Closest to 'notable trap' (t5). The misconception explicitly states developers wrongly believe lazy objects are 'only useful for ORMs' when they're broadly useful for any expensive service. Additionally, common_mistakes highlight confusion between ghost (modifies in place) vs proxy (returns new instance) semantics, and unexpected behaviour when accessing uninitialized objects — documented gotchas most PHP 8.4 developers will eventually learn.

About DEBT scoring →

TL;DR

PHP 8.4 native lazy objects defer object initialisation until first property access — previously requiring proxy libraries, now built into the engine via ReflectionClass.

Explanation

Two strategies: ghost objects (ReflectionClass::newLazyGhost) — same class, initialiser called on first access; virtual proxies (ReflectionClass::newLazyProxy) — returns a different instance on first access. Initialiser receives the uninitialised object. Skipping initialisation: markLazyObjectAsInitialized(). Reset: resetAsLazyGhost(). Use cases: expensive service construction (DB connections, HTTP clients) in DI containers, lazy loading related entities in ORMs. PHP 8.4 lazy objects replace Doctrine/Symfony proxy generator libraries for simple cases. Properties can be marked lazy individually with ReflectionProperty::setRawValueWithoutLazyInitialization().

Common Misconception

Lazy objects are only useful for ORMs — they're broadly useful in DI containers to defer construction of any expensive service until it's actually needed.

Why It Matters

Native lazy objects eliminate the need for generated proxy classes in frameworks — reducing complexity and improving performance of DI container bootstrapping.

Common Mistakes

  • Using lazy objects for services that are always used — adds overhead without benefit.
  • Not understanding ghost vs proxy — ghost modifies in place, proxy returns new instance.
  • Accessing uninitialized lazy object in a context that doesn't trigger initialisation.

Code Examples

✗ Vulnerable
// Before PHP 8.4 — manual proxy:
class LazyDbConnection {
    private ?PDO $pdo = null;
    public function query(string $sql): array {
        $this->pdo ??= new PDO(DB_DSN);
        return $this->pdo->query($sql)->fetchAll();
    }
}
✓ Fixed
// PHP 8.4 native lazy ghost:
$reflector = new ReflectionClass(DbConnection::class);
$lazy = $reflector->newLazyGhost(function(DbConnection $obj) {
    // Called only on first property access:
    $obj->__construct(getenv('DATABASE_URL'));
});

// Injected into container — no connection until actually used
$container->bind(DbConnection::class, fn() => $lazy);

Edited 23 Mar 2026
Views 97
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 2 pings W 0 pings T 3 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 15 PetalBot 12 SEMrush 8 Ahrefs 7 Unknown AI 5 Google 5 Perplexity 3 Scrapy 2 Applebot 2 DuckDuckGo 2 ChatGPT 1 Meta AI 1 Twitter/X 1 Bing 1 Brave Search 1
crawler 62 crawler_json 1 your_contextpost 1 pre-tracking 2
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
PHP php A server-side scripting language that generates web pages and APIs — the code runs on the server, and only its output (usually HTML or JSON) reaches the browser.

PHP is often the first server-side language people meet, and understanding its execution model — script starts fresh on every request, no memory between requests — explains most of how the web backend works: sessions, databases, and caching all exist to bridge that per-request amnesia.

💡 Start with PHP 8.x, declare(strict_types=1), and PDO — skip any tutorial that mentions mysql_query().

Ask Codex about PHP →
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: High
⚡ Quick Fix
Use ReflectionClass::newLazyGhost() for deferred service initialisation. Prefer for expensive objects (DB, HTTP, cache) in DI containers.
📦 Applies To
PHP 8.4+ web cli queue-worker Symfony Laravel
🔗 Prerequisites
🔍 Detection Hints
newLazyGhost|newLazyProxy
Auto-detectable: ✗ No
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Class


✓ schema.org compliant