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

Copy-on-Write (CoW) in PHP Arrays

PHP PHP 7.0+ Intermediate
debt(d7/e5/b3/t7)
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.tools list is empty. CoW-triggered memory spikes are silent at the code level — no linter or compiler flags an accidental write inside a function receiving a large array. Discovery typically requires runtime memory profiling or careful review. A specialist memory profiler could catch it, but it won't point specifically to the CoW trigger without deliberate investigation, placing this closer to d7 than 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 make the copy explicit with '$local = $array;', which sounds like a one-liner, but the common_mistakes reveal that the real remediation involves auditing all call sites that pass large arrays to check for accidental writes, removing unnecessary & references, and restructuring loops that hold multiple references — this typically touches multiple functions or files. It is not a purely architectural rework, but it is more than a single-line swap.

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

Closest to 'localised tax' (b3). CoW applies broadly across web and cli contexts, but its impact is confined to code paths that work with large arrays. Most everyday code is unaffected; the burden only materialises for developers working in performance-sensitive areas. It does not shape the entire codebase architecture, so the tax is localised rather than pervasive.

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

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field states explicitly that passing a large array by value is believed to be expensive, when in PHP 7+ it is only expensive if the function modifies the array. This directly contradicts the mental model developers carry from most other languages (C, Java, Python) where pass-by-value of a large structure is always a copy cost. The 'obvious' assumption — that adding & avoids cost — can actually add complexity without benefit for read-only operations, and the accidental single-element append triggering a 100MB copy is a particularly counter-intuitive surprise.

About DEBT scoring →

Also Known As

copy on write CoW arrays PHP array copying lazy copy

TL;DR

PHP arrays are not copied when assigned or passed to functions — they share the same internal buffer until one copy is modified. Only then does PHP perform a real copy. This makes reading large arrays cheap but silent mutations expensive.

Explanation

Copy-on-write is the mechanism PHP uses to make arrays behave as value types without the cost of eager copying. When you write '$b = $a' both variables point to the same array data with a shared reference count of 2. When either variable is modified — an element is added, changed, or deleted — PHP checks the reference count: if it's greater than 1, it duplicates the array data before modifying it. This copy is called a 'CoW split'. The result is that pure reads are free, but writes on shared arrays incur a full copy. Functions that receive an array and modify it (even sort(), which modifies in place) trigger a CoW split on the caller's array.

Common Misconception

Passing an array to a function by value is expensive for large arrays. In PHP 7+ it is only expensive if the function modifies the array. A function that iterates and reads an array without writing incurs only the cost of incrementing and decrementing a reference counter.

Why It Matters

CoW explains performance characteristics that seem counter-intuitive: passing a 100MB array to a read-only function costs almost nothing, but a function that appends a single element to that array triggers a 100MB copy. Knowing this helps you write functions that avoid accidental writes, use generators instead of building large intermediate arrays, and profile memory spikes correctly.

Common Mistakes

  • Using array_push() inside a function that receives an array parameter and expecting the caller's array to change — CoW means the function works on its own copy.
  • Adding & (pass by reference) to avoid CoW — this is usually unnecessary for read-only operations and adds complexity; only use & when you genuinely need to mutate the caller's variable.
  • Holding multiple references to a large array in a loop — each iteration that writes triggers a CoW split per reference; restructure to minimise shared-write patterns.
  • Assuming generators are always better than arrays — generators have overhead per yield; for small arrays, eager construction is simpler and often faster.

Code Examples

✗ Vulnerable
<?php
// ❌ Unexpected CoW split — $data is copied inside processAll() due to sort()
function processAll(array $data): array
{
    sort($data); // Triggers full copy of $data — the caller's copy is unaffected
    // ...but caller may not realise a 50MB copy just happened
    return $data;
}

// ❌ Building a large intermediate array when a generator would do
function getAllRows(PDO $db): array
{
    $rows = [];
    foreach ($db->query('SELECT * FROM logs') as $row) {
        $rows[] = $row; // Entire result set in memory
    }
    return $rows;
}
✓ Fixed
<?php
// ✅ Make the copy intent explicit when you know a write is coming
function processAll(array $data): array
{
    // $data is already a CoW-detached copy once we sort it
    // — explicit variable name makes it clear this is a working copy
    sort($data);
    return $data;
}

// ✅ Generator avoids building large intermediate array
function getAllRows(PDO $db): Generator
{
    $stmt = $db->query('SELECT * FROM logs');
    while ($row = $stmt->fetch()) {
        yield $row; // One row in memory at a time
    }
}

Added 23 Mar 2026
Edited 13 Jun 2026
Views 90
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 1 ping S 0 pings S 1 ping 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 1 ping W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 1 ping S 1 ping S 0 pings M
No pings yet today
Amazonbot 1
PetalBot 11 Amazonbot 10 Ahrefs 7 SEMrush 7 Perplexity 5 ChatGPT 3 Google 3 Bing 3 Scrapy 2 Applebot 2 Meta AI 1 Twitter/X 1 Brave Search 1
crawler 54 crawler_json 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
⚡ Quick Fix
If a function receives a large array and must modify it, make the copy explicit: '$local = $array;' communicates intent clearly. If the function must not modify the caller's copy, this is already guaranteed by CoW — no extra steps needed.
📦 Applies To
PHP 7.0+ web cli

✓ schema.org compliant