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

Thread Safety

Concurrency PHP 7.0+ Intermediate
debt(d7/e7/b7/t9)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints list PHPStan, but the metadata explicitly notes automated detection is 'no' — PHPStan can flag static state patterns (`static $|static::`) but cannot reason about concurrency correctness or shared resource contention. Most thread-safety bugs in PHP (especially under Swoole/FrankenPHP) surface only in runtime testing under load or via careful code review of mutable static state.

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix says 'prefer immutable objects and stateless functions' and 'avoid static mutable state' — but converting mutable static/global state to immutable, stateless designs touches every class and component that shares state. This is not a single-file fix; it's a design-level refactor that ripples across the codebase wherever shared mutable state was assumed safe.

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

Closest to 'strong gravitational pull' (b7). The choice applies to web, cli, and queue-worker contexts, meaning it affects every PHP execution model. Under modern runtimes like Swoole or FrankenPHP, every future maintainer must understand and respect thread-safety constraints when writing or modifying any stateful code. Incorrect assumptions compound over time, shaping how services, caches, and shared resources are designed throughout the system.

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

Closest to 'catastrophic trap — the obvious way is always wrong' (t9). The misconception field states exactly this: 'PHP is immune to concurrency issues because it's single-threaded.' This is the canonical wrong belief, deeply ingrained in PHP culture. A competent developer familiar with traditional PHP-FPM development will confidently use static mutable state, assume global state is process-local everywhere, and ignore locking — all of which are catastrophically wrong under Swoole/FrankenPHP and subtly wrong even in PHP-FPM when shared resources are involved.

About DEBT scoring →

TL;DR

Thread-safe code produces correct results regardless of how multiple threads interleave — achieved through immutability, atomic operations, or synchronisation primitives.

Explanation

Code is thread-safe if it behaves correctly when multiple threads execute it simultaneously. Strategies: (1) Immutability — objects that cannot be modified are inherently thread-safe. (2) Thread-local storage — each thread has its own copy of mutable state. (3) Atomic operations — hardware-level indivisible read-modify-write. (4) Synchronisation — mutexes/locks. (5) Stateless design — functions with no shared state are thread-safe. In PHP: the language runtime is not thread-safe by default (ZTS — Zend Thread Safety — is a compile option). PHP-FPM uses separate processes (not threads) so most PHP code is safe. Extensions may not be ZTS-compiled. Swoole and ReactPHP introduce real concurrency within one process.

Common Misconception

PHP is immune to concurrency issues because it's single-threaded — PHP-FPM runs many processes concurrently, all hitting shared resources (DB, files, cache). Concurrency bugs are real.

Why It Matters

Stateless, immutable design is the most reliable path to thread safety — and also makes code easier to test and reason about.

Common Mistakes

  • Mutable static/global state in classes — shared across requests in Swoole/FrankenPHP.
  • Assuming global state is safe in PHP-FPM — each process has its own, but shared resources (DB, Redis) still need protection.
  • Not marking PHP extensions as ZTS-safe when using threaded PHP.

Code Examples

✗ Vulnerable
// Mutable static — breaks in Swoole/FrankenPHP:
class RequestContext {
    private static ?User $currentUser = null;
    public static function setUser(User $u): void { self::$currentUser = $u; }
}
✓ Fixed
// Immutable request context — safe in all runtimes:
class RequestContext {
    public function __construct(
        public readonly User $user,
        public readonly string $requestId,
    ) {}
}
// Pass as dependency, not global static

Added 23 Mar 2026
Edited 5 Apr 2026
Views 103
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 1 ping S 0 pings M 1 ping T 1 ping W 2 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 2 pings S 0 pings S 2 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 1 ping S
Amazonbot 1
No pings yesterday
Amazonbot 8 Perplexity 8 Google 7 Ahrefs 7 ChatGPT 7 PetalBot 7 Scrapy 5 Bing 4 SEMrush 4 Unknown AI 3 Claude 3 Applebot 2 Meta AI 1 Twitter/X 1
crawler 59 crawler_json 7 pre-tracking 1
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Thread concurrency A thread is the smallest unit of execution that your operating system can schedule. Multiple threads within the same program can run at the same time, sharing memory but each following its own sequence of instructions.

Threads let programs do multiple things simultaneously—keeping interfaces responsive, processing requests in parallel, and using multi-core CPUs effectively. Understanding threads is essential for writing fast, responsive software.

💡 If two threads touch the same variable and at least one writes, protect it with a lock—no exceptions.

Ask Codex about Thread →
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Prefer immutable objects and stateless functions. Avoid static mutable state — breaks under Swoole/FrankenPHP. Protect shared resources (files, DB, cache) with locks.
📦 Applies To
PHP 7.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
static \$|static::
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Class Tests: Update
CWE-362 CWE-820


✓ schema.org compliant