📁 Volume II: Laravel Performance Tuning Kit

📐 Topic 22: SplFixedArray

The PHP array lie — why normal arrays are actually hash maps.

"PHP arrays are not arrays. They are hash maps.
Every key-value pair consumes 5-10x more memory than a real C array.
If you know the size of your array in advance, use SplFixedArray.
It saves 70-80% memory and is slightly faster."
⚠️ THE ARRAY LIE

Most PHP developers believe that [] is a lightweight array. In reality, PHP arrays are hash tables with significant overhead: bucket structures, hash values, pointer arrays, and memory alignment. SplFixedArray is a true C array — contiguous memory blocks with minimal overhead.

🔍 What's Wrong With Normal PHP Arrays?

PHP ARRAY (Hash Table) INTERNAL STRUCTURE ═══════════════════════════════════════════════════════════════════ When you create: $array = [1, 2, 3, 4, 5]; PHP actually allocates: ┌─────────────────────────────────────────────────────────────────┐ │ Hash Table Structure: │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Bucket Array (size = power of 2, e.g., 8) │ │ │ │ ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │ │ │ │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ │ │ │ │ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ Each Bucket contains: │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ • key (string or int) - 24 bytes │ │ │ │ • value (zval) - 16 bytes │ │ │ │ • hash value - 8 bytes │ │ │ │ • pointer to next bucket - 8 bytes │ │ │ │ • memory alignment padding - ~8 bytes │ │ │ │ Total per element: ~64-80 bytes │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ For 100,000 elements: ~8MB of overhead! SPLFIXEDARRAY (True C Array) ═══════════════════════════════════════════════════════════════════ When you create: $array = new SplFixedArray(100000); PHP allocates: ┌─────────────────────────────────────────────────────────────────┐ │ Contiguous memory block: │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ [0][1][2][3][4][5][6][7][8][9]...[99999] │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ Each element: just the value (16 bytes for zval) │ │ No bucket structures. No hash values. No pointer chains. │ │ │ │ Total per element: ~16-24 bytes │ └─────────────────────────────────────────────────────────────────┘ For 100,000 elements: ~2MB of memory (75% less!)
THE DIFFERENCE

PHP arrays are optimized for flexibility (associative arrays, dynamic resizing). SplFixedArray is optimized for memory efficiency and speed (fixed size, integer keys).

📊 Memory Comparison: PHP Array vs SplFixedArray

Number of Elements PHP Array Memory SplFixedArray Memory Saving
1,000 ~0.5 MB ~0.1 MB 80%
10,000 ~5 MB ~1 MB 80%
100,000 ~50 MB ~10 MB 80%
1,000,000 ~500 MB ~100 MB 80%
10,000,000 ~5 GB (crashes) ~1 GB 80% (server survives)
REAL-WORLD EXAMPLE

Processing a 1,000,000-row export:

🔧 Using SplFixedArray

BASIC USAGE
// Create with known size
$array = new SplFixedArray(10000);

// Set values (index must be within size)
for ($i = 0; $i < 10000; $i++) {
    $array[$i] = $i * 2;
}

// Get values
$value = $array[500];  // O(1) - direct memory access

// Get size
$size = $array->getSize();  // 10000

// Convert to PHP array (when you need flexibility)
$normalArray = $array->toArray();

// Convert from PHP array
$fixedArray = SplFixedArray::fromArray($normalArray);

// Resize (grow or shrink)
$array->setSize(20000);  // Grows, new elements are NULL

// Iterate
foreach ($array as $key => $value) {
    echo "$key: $value\n";
}
LIMITATIONS

⚡ Performance Comparison: Read/Write Speed

Operation PHP Array SplFixedArray Difference
Write 1M elements ~0.15 sec ~0.12 sec 20% faster
Read 1M elements (sequential) ~0.08 sec ~0.05 sec 37% faster
Read 1M elements (random) ~0.10 sec ~0.06 sec 40% faster
THE BOTTOM LINE

SplFixedArray is 20-40% faster and uses 70-80% less memory than normal PHP arrays for large, fixed-size, integer-keyed datasets.

🌍 Real-World Use Cases for SplFixedArray

USE SPLFIXEDARRAY WHEN:
USE NORMAL ARRAYS WHEN:

📝 Example: Processing Large CSV Files

BEFORE: PHP ARRAY (MEMORY HEAVY)
function processLargeCsv($filename)
{
    $rows = [];
    $handle = fopen($filename, 'r');
    
    while (($row = fgetcsv($handle)) !== false) {
        $rows[] = $row;  // 10M rows = 5GB memory
    }
    
    fclose($handle);
    
    foreach ($rows as $row) {
        // Process row
    }
}
AFTER: SPLFIXEDARRAY (MEMORY EFFICIENT)
function processLargeCsv($filename)
{
    // First pass: count rows
    $lineCount = 0;
    $handle = fopen($filename, 'r');
    while (fgets($handle) !== false) $lineCount++;
    fclose($handle);
    
    // Allocate exact size
    $rows = new SplFixedArray($lineCount);
    
    // Second pass: store rows
    $handle = fopen($filename, 'r');
    $index = 0;
    while (($row = fgetcsv($handle)) !== false) {
        $rows[$index] = $row;
        $index++;
    }
    fclose($handle);
    
    // Process
    foreach ($rows as $row) {
        // Process row
    }
    
    // Memory: 1GB instead of 5GB for 10M rows!
}
MEMORY SAVINGS

For a 10,000,000 row CSV file:

Note: For truly massive files, streaming is better than storing in memory at all. Use SplFixedArray when you must store all rows in memory.

🔄 Converting Between PHP Arrays and SplFixedArray

// PHP array to SplFixedArray
$normalArray = [1, 2, 3, 4, 5];
$fixedArray = SplFixedArray::fromArray($normalArray);
// $fixedArray[0] = 1, $fixedArray[1] = 2, etc.

// SplFixedArray to PHP array
$fixedArray = new SplFixedArray(5);
$fixedArray[0] = 'a';
$fixedArray[1] = 'b';
$fixedArray[2] = 'c';
$fixedArray[3] = 'd';
$fixedArray[4] = 'e';
$normalArray = $fixedArray->toArray();
// $normalArray = ['a', 'b', 'c', 'd', 'e']

// Convert associative array? Can't (SplFixedArray requires integer keys)
$assoc = ['name' => 'John', 'age' => 30];
// $fixed = SplFixedArray::fromArray($assoc);  // WARNING: String keys become 0, 1!

// Better: Use SplFixedArray for sequential data only
⚠️ WARNING: STRING KEYS

SplFixedArray::fromArray(['a' => 1, 'b' => 2]) will convert string keys to numeric indices (0, 1). The original keys are lost. Only use SplFixedArray for sequentially indexed arrays.

❌ When NOT to Use SplFixedArray

AVOID SPLFIXEDARRAY WHEN:
📌 THE RULE: Use SplFixedArray when you need to store large (100k+), fixed-size, sequentially indexed datasets. For everything else, normal arrays are fine.

📝 Topic 22 Summary: SplFixedArray

Feature PHP Array SplFixedArray
Memory per 1M integers ~500 MB ~100 MB
Read speed (1M random) ~0.10 sec ~0.06 sec
Write speed (1M) ~0.15 sec ~0.12 sec
String keys allowed? Yes No
Dynamic resizing Yes (fast) Yes (slow, recreate)
array_* functions Yes No (convert first)
📌 THE RULE: For large, fixed-size, integer-keyed datasets, SplFixedArray saves 70-80% memory and is 20-40% faster than normal PHP arrays. For small datasets or associative arrays, stick with normal arrays.
NEXT TOPIC PREVIEW

Topic 23: Lazy Resolution for Services — Don't pay for services you don't use. How to defer service instantiation until actually needed. Save memory and CPU on every request.