12 essential data structures for PHP developers. Each one explained with Big O complexity, animated visuals, and real code samples you can copy.
SplFixedArray / arrayFixed-size, contiguous block of memory. Elements are stored sequentially and accessed by index in constant time. The foundation of most other data structures.
arr[0] = 7
Complexity
When to use
// PHP arrays are dynamic, SplFixedArray is fixed-size
$fixed = new SplFixedArray(5);
$fixed[0] = 10; // O(1) - direct index
$fixed[1] = 20;
$fixed[2] = 30;
$val = $fixed[2]; // O(1) -> 30
// Resize is expensive - allocates new internal storage
$fixed->setSize(10); // O(n)
// Regular fixed-size simulation
$nums = [10, 20, 30, 40, 50];
$nums[0] = 99; // O(1)
sort($nums); // O(n log n)
$idx = array_search(30, $nums); // O(n)arrayResizable array that automatically grows when capacity is exceeded. The most commonly used data structure in most languages. Doubles its internal storage when full, giving amortized O(1) appends.
arr[0] = 7
Complexity
When to use
$names = ["Alice", "Bob", "Charlie"];
$names[] = "Diana"; // O(1) amortized - append
array_splice($names, 1, 0, ["Eve"]); // O(n) - insert at index
array_pop($names); // O(1) - remove last
array_shift($names); // O(n) - remove first
$has = in_array("Bob", $names); // O(n)
$idx = array_search("Bob", $names); // O(n)
sort($names); // O(n log n)
$squares = array_map(fn($x) => $x * $x, range(0, 9)); // O(n)array (push/pop)Last-In-First-Out (LIFO) collection. Only the top element is accessible. Used for tracking state that must be unwound in reverse order.
Push 10
Complexity
When to use
// Use array as stack
$stack = [];
array_push($stack, 10); // O(1)
array_push($stack, 20);
array_push($stack, 30);
$top = end($stack); // O(1) - peek -> 30
$val = array_pop($stack); // O(1) - pop -> 30
// Interview pattern: valid parentheses
function isValid(string $s): bool {
$pairs = ["(" => ")", "[" => "]", "{" => "}"];
$st = [];
foreach (str_split($s) as $c) {
if (isset($pairs[$c])) $st[] = $pairs[$c];
elseif (empty($st) || array_pop($st) !== $c) return false;
}
return empty($st);
}SplQueueFirst-In-First-Out (FIFO) collection. Elements are added at the back and removed from the front. Fundamental for breadth-first processing.
Enqueue 10
Complexity
When to use
$queue = new SplQueue();
$queue->enqueue("Task A"); // O(1)
$queue->enqueue("Task B");
$queue->enqueue("Task C");
$first = $queue->bottom(); // O(1) - peek front
$val = $queue->dequeue(); // O(1) - dequeue -> "Task A"
$empty = $queue->isEmpty(); // check
// Interview pattern: BFS
function bfs(?TreeNode $root): void {
if (!$root) return;
$q = new SplQueue();
$q->enqueue($root);
while (!$q->isEmpty()) {
$node = $q->dequeue();
echo $node->val . " ";
if ($node->left) $q->enqueue($node->left);
if ($node->right) $q->enqueue($node->right);
}
}array (associative)Maps keys to values using a hash function for near-constant-time lookups. The single most important data structure for coding interviews. Every language has a built-in implementation.
hash("age") = 0
Complexity
When to use
$prices = ["apple" => 3, "banana" => 5];
$prices["cherry"] = 2; // O(1) - add
$prices["apple"] = 10; // O(1) - update
$has = array_key_exists("banana", $prices); // O(1)
unset($prices["cherry"]); // O(1)
$count = $prices["mango"] ?? 0; // O(1) - null coalescing
// Interview pattern: Two Sum
function twoSum(array $nums, int $target): array {
$seen = [];
foreach ($nums as $i => $num) {
$need = $target - $num;
if (isset($seen[$need])) return [$seen[$need], $i]; // O(1)
$seen[$num] = $i; // O(1)
}
return [];
}array_flip (keys as set)Unordered collection of unique elements. Uses hashing internally for O(1) membership testing. Supports mathematical set operations like union, intersection, and difference.
hash("age") = 0
Complexity
When to use
// PHP has no native Set - simulate with array keys
$s = array_flip([1, 2, 3, 4, 5]); // values become keys
$s[6] = true; // O(1) - add
unset($s[1]); // O(1) - remove
$has = isset($s[4]); // O(1) -> true
// Set operations using array functions
$other = array_flip([4, 5, 6, 7]);
$inter = array_intersect_key($s, $other); // intersection
$union = $s + $other; // union
$diff = array_diff_key($s, $other); // difference
// Interview pattern: contains duplicate
function containsDuplicate(array $nums): bool {
return count($nums) !== count(array_unique($nums));
}SplDoublyLinkedListSequence of nodes where each node points to the next (singly linked) or both next and previous (doubly linked). Efficient insertion and deletion at any known position, but no index-based access.
traversing: 5
Complexity
When to use
$list = new SplDoublyLinkedList();
$list->push(10); // O(1) - add to tail
$list->push(20);
$list->unshift(5); // O(1) - add to head
$list->add(1, 15); // O(n) - insert at index
$first = $list->bottom(); // O(1) - peek head -> 5
$last = $list->top(); // O(1) - peek tail -> 20
$list->pop(); // O(1) - remove from tail
$list->shift(); // O(1) - remove from head
// Iterate
for ($list->rewind(); $list->valid(); $list->next()) {
echo $list->current() . " "; // 15 10
}sorted arrayCollection of unique elements maintained in sorted order, typically backed by a balanced binary search tree (red-black tree). Supports range queries and O(log n) min/max.
search(8)
Complexity
When to use
// Manual sorted array - maintain order on insert
$sorted = [1, 3, 5, 8, 9];
// Binary search for insertion point - O(log n)
function sortedInsert(array &$arr, int $val): void {
$lo = 0; $hi = count($arr);
while ($lo < $hi) {
$mid = intdiv($lo + $hi, 2);
if ($arr[$mid] < $val) $lo = $mid + 1;
else $hi = $mid;
}
array_splice($arr, $lo, 0, [$val]); // O(n) shift
}
sortedInsert($sorted, 4); // [1, 3, 4, 5, 8, 9]
$min = $sorted[0]; // O(1) -> 1
$max = end($sorted); // O(1) -> 9
// Range query
$between = array_filter($sorted, fn($x) => $x >= 4 && $x <= 8);ksort arrayKey-value pairs maintained in sorted key order, typically backed by a balanced BST. Enables ordered iteration and range lookups that hash maps cannot provide.
search(8)
Complexity
When to use
$sd = ["banana" => 2, "apple" => 5, "cherry" => 1];
$sd["date"] = 3; // O(1) - add
$val = $sd["apple"]; // O(1) -> 5
unset($sd["cherry"]); // O(1)
// Sort by keys - O(n log n)
ksort($sd);
// Iterate in sorted key order
foreach ($sd as $key => $value) {
echo "$key: $value\n";
}
// apple: 5, banana: 2, date: 3
$keys = array_keys($sd);
$firstKey = $keys[0]; // "apple"
$lastKey = end($keys); // "date"SplPriorityQueueCollection where elements are dequeued by priority rather than insertion order. Typically implemented as a binary heap. Essential for shortest-path algorithms and top-K problems.
min-heap
Complexity
When to use
$pq = new SplPriorityQueue();
// Higher priority number = dequeued first (max-heap)
$pq->insert("low", 1); // O(log n)
$pq->insert("high", 3);
$pq->insert("medium", 2);
$top = $pq->top(); // O(1) - peek -> "high"
$val = $pq->extract(); // O(log n) - extract -> "high"
// Min-heap: negate priorities
$minPq = new SplPriorityQueue();
$minPq->insert("C", -3);
$minPq->insert("A", -1);
$minPq->insert("B", -2);
$minPq->extract(); // O(log n) -> "A" (priority -1)
// Set extraction mode for key-priority pairs
$pq->setExtractFlags(SplPriorityQueue::EXTR_BOTH);flock + APCuThread-safe hash map designed for concurrent read/write access from multiple threads. Uses fine-grained locking or lock-free techniques instead of a single global lock.
hash("age") = 0
Complexity
When to use
// PHP is single-threaded per request; use mutex for shared state
// With parallel extension (PHP 8.2+)
// Simple file-based locking for shared cache
function atomicGet(string $key): mixed {
$fp = fopen("/tmp/cache_$key.lock", "c+");
flock($fp, LOCK_SH); // shared read lock
$data = apcu_fetch($key); // O(1) - APCu cache read
flock($fp, LOCK_UN);
fclose($fp);
return $data;
}
function atomicSet(string $key, mixed $val): void {
$fp = fopen("/tmp/cache_$key.lock", "c+");
flock($fp, LOCK_EX); // exclusive write lock
apcu_store($key, $val); // O(1) - APCu cache write
flock($fp, LOCK_UN);
fclose($fp);
}substr / array_sliceZero-copy view over a contiguous region of memory. Lets you reference a portion of an array or buffer without allocating new memory. Critical for performance-sensitive parsing and processing.
Span[0..3] = [1, 2, 3]
Complexity
When to use
// substr - string slicing (returns copy)
$data = "Hello, World!";
$chunk = substr($data, 7, 5); // O(k) -> "World"
// array_slice - array slicing (returns copy)
$nums = [10, 20, 30, 40, 50];
$slice = array_slice($nums, 1, 3); // O(k) -> [20, 30, 40]
// pack/unpack for binary data views
$bin = pack("N2", 42, 100); // pack two 32-bit ints
$vals = unpack("N2val", $bin); // O(1) -> [val1 => 42, val2 => 100]
// SplFixedArray for contiguous memory
$buf = SplFixedArray::fromArray([1, 2, 3, 4, 5]);
$buf[0] = 99; // O(1) - direct access
// No true zero-copy view in PHP - slicing always copiesAverage-case time complexity. * = amortized.
| Structure | Access | Search | Insert | Delete |
|---|---|---|---|---|
| Array | O(1) | O(n) | O(n) | O(n) |
| Dynamic Array | O(1) | O(n) | O(1)* | O(n) |
| Stack | O(n) | O(n) | O(1)* | O(1) |
| Queue | O(n) | O(n) | O(1)* | O(1) |
| Hash Map | O(1) | O(1) | O(1)* | O(1) |
| Hash Set | N/A | O(1) | O(1)* | O(1) |
| Linked List | O(n) | O(n) | O(1) | O(1) |
| Sorted Set | O(n) | O(log n) | O(log n) | O(log n) |
| Sorted Map | O(log n) | O(log n) | O(log n) | O(log n) |
| Priority Queue | O(n) | O(n) | O(log n) | O(log n) |
| Concurrent Map | O(1) | O(1) | O(1)* | O(1) |
| Memory View | O(1) | O(n) | N/A | N/A |
| I need to... | Use |
|---|---|
| Store items by index, resize dynamically | List / Dynamic Array |
| Map keys to values with O(1) lookup | HashMap / Dictionary |
| Track unique items, check existence in O(1) | HashSet / Set |
| Last-in-first-out (undo, DFS, brackets) | Stack |
| First-in-first-out (BFS, task queues) | Queue |
| Keep elements sorted at all times | SortedSet / TreeSet |
| Process items by priority (Dijkstra, top-K) | PriorityQueue / Heap |
| Insert/delete at a known position in O(1) | LinkedList |
| Sorted key-value pairs | SortedDictionary / TreeMap |
| Thread-safe shared cache | ConcurrentDictionary |
| Slice arrays/strings without copying | Span / Slice / memoryview |
The most commonly used are dynamic arrays (List/ArrayList/vector), hash maps (Dictionary/HashMap/dict), and hash sets. For interviews, also know stacks, queues, trees, and priority queues. These cover 90%+ of coding interview problems.
Start with the dynamic array and hash map. Together they solve the majority of interview problems. Then learn stacks (for DFS, bracket matching) and queues (for BFS). After that, tackle trees, heaps, and graphs.
No. Big O measures algorithmic complexity, not language-specific performance. A hash map lookup is O(1) whether you use Python dict, Java HashMap, or C# Dictionary. Constant factors differ (C++ is faster than Python in wall-clock time), but Big O is the same.
It depends on the language runtime. Check the PHP standard library documentation for heap or priority queue support.
Practice with an AI interviewer that asks you to implement, optimize, and explain data structure choices in real time.
Try a free mock interviewarrow_forward