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

Memory Visibility & Cache Coherence

Concurrency Advanced
debt(d8/e5/b5/t7)
d8 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production until users hit it' (d9), but slightly better (d8) because PHPStan is listed as a tool that can catch some patterns, though automated detection is explicitly marked 'no' in detection_hints. The code_pattern (static property used as cache in Swoole shared between coroutines) requires recognising a specific architectural pattern — this is largely invisible and won't surface until stale data causes observable bugs in production, often intermittently.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests swapping static PHP variables for Redis when using Swoole/RoadRunner — this is not a single-line patch but requires identifying all shared mutable state, replacing it with a coordinated store (Redis), and validating correctness. In Swoole/RoadRunner contexts this can touch multiple files and components, though it doesn't require full architectural rework.

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

Closest to 'persistent productivity tax' (b5). The issue applies across web, cli, and queue-worker contexts (all three listed in applies_to). Once a team adopts Swoole or RoadRunner, every use of static state or APCu becomes suspect and must be reviewed. This imposes an ongoing mental tax on every developer writing shared state logic, but doesn't reshape the entire system architecture.

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

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception is explicit: PHP developers assume FPM process isolation eliminates all memory visibility problems, then are surprised when APCu staleness, Swoole coroutine sharing, or forked-process coordination causes subtle bugs. The behaviour directly contradicts the 'PHP is safe from concurrency issues' mental model most PHP developers hold, making this a serious cognitive trap without being universally catastrophic.

About DEBT scoring →

Also Known As

memory barrier cache coherence visibility happens-before

TL;DR

In multi-processor systems, each CPU has a cache — writes by one CPU may not be visible to others without memory barriers. PHP's process-per-request model avoids most visibility issues.

Explanation

Modern CPUs have L1/L2/L3 caches. Without synchronisation, CPU A's write to a variable may sit in its cache, invisible to CPU B. Memory barriers (fences) force cache flushes ensuring visibility. In high-level languages: Java's volatile, C's atomic, and Go's sync package handle barriers automatically. PHP's PHP-FPM model: each request runs in a separate process with no shared memory — memory visibility issues don't exist within a single request. They arise with: APCu (shared memory between workers), Swoole coroutines sharing state, and pcntl_fork() child processes.

Common Misconception

PHP developers never encounter memory visibility issues — PHP-FPM's process isolation prevents most issues, but shared memory (APCu), Swoole coroutines, and forked processes can all exhibit visibility problems.

Why It Matters

An APCu cache value written in one PHP-FPM worker may not be immediately visible in another worker's CPU cache — APCu uses shared memory with spinlocks to ensure coherence, but developers must understand when stale values are possible.

Common Mistakes

  • Assuming APCu reads are always fresh — there is a window where a cached value may be stale.
  • Sharing mutable state between Swoole coroutines without coordination.
  • Forked child processes modifying shared APCu state without coordination.
  • Expecting process-local variables to be shared across FPM workers — each worker has its own memory.

Code Examples

✗ Vulnerable
// Incorrect assumption: APCu updates are instantly visible:
// Worker A writes:
apcu_store('config_version', 42);

// Worker B reads immediately after (different CPU core):
$version = apcu_fetch('config_version'); // Might still see 41!
// APCu uses shared memory but CPU cache may not be flushed yet
✓ Fixed
// Design around eventual visibility:
// 1. Use a version key with TTL to expire stale values:
apcu_store('config', $data, 60); // Expire after 60s max staleness

// 2. For critical consistency: use Redis (single-process server)
$redis->set('config_version', 42);

// 3. For Swoole: use channel or atomic for coordination:
$chan = new Swoole\Coroutine\Channel(1);
// Producer writes, consumer reads via channel — guaranteed visibility

Added 16 Mar 2026
Edited 22 Mar 2026
Views 101
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping S 0 pings M 1 ping T 1 ping W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 2 pings T 0 pings W 1 ping T 3 pings F 2 pings S 1 ping S 0 pings M 0 pings T 1 ping W 1 ping T 1 ping F 1 ping S 10 pings S 3 pings M 1 ping T 1 ping W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M
No pings yet today
No pings yesterday
Google 29 Amazonbot 8 Ahrefs 7 ChatGPT 7 SEMrush 7 PetalBot 4 Unknown AI 3 Bing 3 Brave Search 3 Scrapy 2 Applebot 2 Perplexity 1 Meta AI 1 Majestic 1 Twitter/X 1 Baidu 1
crawler 74 crawler_json 5 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
In PHP-FPM, each worker has independent memory — no visibility issues between workers; when using Swoole/RoadRunner with coroutines, use Redis for shared state never static PHP variables
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Static property used as cache in Swoole worker shared between coroutines; assuming FPM worker changes visible to other workers
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: File Tests: Update
CWE-362


✓ schema.org compliant