SplFixedArray, SplDoublyLinkedList — typed collections
Concept
PHP's SPL (Standard PHP Library) provides typed, memory-efficient data structures that outperform plain arrays in specific scenarios.
SplFixedArray: An array with a fixed size, storing only integers (by key and by value). Unlike a PHP array (which is a hash table with overhead per entry), SplFixedArray uses a direct memory block. Memory advantage: A SplFixedArray of 1 million integers uses ~14 MB. A PHP array with 1 million integers uses ~100-120 MB.
When to use SplFixedArray:
- You know the size upfront and it won't change.
- You're storing large amounts of integers or sequential numeric data.
- Memory consumption is critical.
SplDoublyLinkedList: A bidirectional linked list. Supports efficient O(1) push/pop at both ends. SplStack and SplQueue extend it with LIFO/FIFO policies.
SplStack: Extends SplDoublyLinkedList. LIFO. push() and pop() at one end.
SplQueue: Extends SplDoublyLinkedList. FIFO. enqueue() at back, dequeue() at front. O(1) for both operations — unlike array_shift() which is O(n).
SplHeap / SplMinHeap / SplMaxHeap: Binary heap implementations. Always gives you min or max efficiently.
SplPriorityQueue: Min-heap with separate priority. insert($value, $priority). Higher priority = dequeued first.
SplObjectStorage: A map from objects to data. Unlike arrays, uses object identity (not serialized keys) — O(1) attach/detach/contains for object keys.
Code Example
<?php
// SplFixedArray — memory-efficient for large integer arrays
$size = 1_000_000;
$fixed = new \SplFixedArray($size);
// Populate (direct index assignment)
for ($i = 0; $i < $size; $i++) {
$fixed[$i] = $i * 2;
}
echo $fixed[500_000]; // 1000000
echo $fixed->getSize(); // 1000000
// Convert to/from regular array
$regular = $fixed->toArray();
$fixed2 = \SplFixedArray::fromArray([1, 2, 3, 4, 5]);
// Resize (expensive — O(n) copy)
$fixed->setSize(2_000_000);
// SplDoublyLinkedList — O(1) at both ends
$dll = new \SplDoublyLinkedList();
$dll->push('end');
$dll->unshift('beginning'); // prepend to front
echo $dll->shift(); // 'beginning' (pop from front)
echo $dll->pop(); // 'end' (pop from back)
// SplStack vs array for stack operations
$spl = new \SplStack();
$arr = [];
// SplStack: push O(1), pop O(1), count O(1)
$spl->push('item');
$item = $spl->pop();
// Array: push O(1), pop O(1) — comparable, but SplStack has iterator
$arr[] = 'item';
$item = array_pop($arr);
// SplQueue vs array_shift — the key performance difference
$queue = new \SplQueue();
$queue->enqueue('first');
$queue->enqueue('second');
$first = $queue->dequeue(); // O(1)
// array_shift is O(n) — re-indexes the entire array
$arr = ['first', 'second'];
$first = array_shift($arr); // O(n) — bad for large queues!
// SplObjectStorage — object identity as keys
$storage = new \SplObjectStorage();
$userA = new stdClass();
$userB = new stdClass();
$storage->attach($userA, ['role' => 'admin']);
$storage->attach($userB, ['role' => 'user']);
$storage->contains($userA); // true
$storage[$userA]; // ['role' => 'admin']
$storage->detach($userA);
// Memory comparison (approximate)
$n = 100_000;
$arr = range(0, $n - 1);
echo memory_get_usage() . ' bytes with array'; // ~8 MB
$fixed = new \SplFixedArray($n);
for ($i = 0; $i < $n; $i++) $fixed[$i] = $i;
// SplFixedArray uses ~1-2 MB for same data