In PHP, what does SplFixedArray give up compared with a plain array, and when is it actually worth using?
answer
- integer indexes 0 to size-1 only
- no [] append; setSize() to grow
- OutOfBoundsException since 8.4
- an object: handle, not copy-on-write
- array_* functions reject it
basics
~20 sSplFixedArray gives up string keys, appending with [], the array_* functions and copy-on-write value semantics. In return it holds exactly the requested number of integer-indexed slots, which can save memory and time for large numeric lists of known size.
solid answer
~40 s`SplFixedArray` is a fixed-size list: indexes run from `0` to `getSize() - 1`, you size it up front (`new SplFixedArray(1000)` or `setSize()`), and `$fa[] = $x` throws `Error` because appending is not supported. An out-of-range index throws `OutOfBoundsException` (since PHP 8.4; a `RuntimeException` before, its parent class). It is an **object**, so passing it to a function shares it instead of copying on write, and functions like `array_map()` or `sort()` reject it; you convert with `toArray()` first. What you gain is exact allocation and a tight index path, useful for large numeric buffers in long-running or CLI code. In current PHP a list-shaped array already stores its values compactly, so I measure with `memory_get_usage()` before switching; for most application code the plain array wins on ergonomics.
code
php · 17 lines<?php
declare(strict_types=1);
$window = new SplFixedArray(3);
foreach ([12, 15, 11] as $i => $ms) {
$window[$i] = $ms;
}
try {
$window[3] = 20; // index outside 0..2
} catch (OutOfBoundsException $e) {
echo $e->getMessage(), "\n"; // Index invalid or out of range
}
$window->setSize(4);
$window[3] = 20; // fine after resizing
echo array_sum($window->toArray()), "\n"; // 58go deeper
Know that SplFixedArray has a fixed size, integer indexes from zero, and needs toArray() before using array functions.
Explain the exceptions it throws, the Error on [] append, and that it is shared as an object handle rather than copied on write.
Justify it only with measured memory or speed gains on large numeric buffers, knowing packed arrays already store values compactly in current PHP.
Treat micro-structures as a last resort after algorithmic and architectural fixes, and require a benchmark before trading array ergonomics for them.
## What SplFixedArray is `SplFixedArray` is an SPL class holding a **fixed number of slots** indexed by integers from `0` to `size - 1`. It behaves like an array for reads and writes by index (`$fa[3] = 'x'`), counts with `count()`, and is iterable with `foreach`. Everything else about it follows from two facts: its size is explicit, and it is an object rather than an array. ```php $buffer = new SplFixedArray(3); // [null, null, null] $buffer[0] = 10; $buffer->setSize(5); // grow; new slots are null $list = SplFixedArray::fromArray([4, 5, 6]); $plain = $list->toArray(); // back to a PHP array ``` ## What it gives up | Plain array can | `SplFixedArray` instead | |---|---| | use string keys and sparse integer keys | only integers `0` to `size - 1` | | grow with `$a[] = $x` | `$fa[] = $x` throws `Error`; call `setSize()` | | return `null` with a warning for a missing key | throws `OutOfBoundsException` for an out-of-range index | | go through `array_map()`, `sort()`, `in_array()` | rejected with `TypeError`; convert with `toArray()` | | be copied on write when passed or assigned | shared as an object handle | Two of these deserve emphasis. - **Value semantics.** A PHP array assigned to another variable or passed to a function behaves as an independent copy (copied lazily, on first write). An `SplFixedArray` is an object: every variable holds a handle to the same instance, so a function that writes into it changes the caller's data. - **`fromArray()` needs integer keys.** `SplFixedArray::fromArray(['a' => 1])` throws `InvalidArgumentException` ("array must contain only positive integer keys"). With `$preserveKeys` left at `true`, integer keys keep their positions and gaps become `null`; pass `false` to pack the values from index `0`. ## What it gains 1. **Exact allocation.** A PHP array that grows by appending doubles its capacity when full, so it can carry unused slots. `SplFixedArray` allocates exactly the size you ask for. 2. **No key bookkeeping.** There are no keys to store or hash; an index maps straight to a slot. PHP 8.5 also sped up its dimension accessors and methods. 3. **Enforced shape.** Out-of-range writes fail loudly instead of silently creating a new key, which can be the point in numeric code. The memory argument is weaker than older blog posts suggest. In current PHP a **list-shaped (packed) array** already stores bare values contiguously, without per-element keys, so the difference is mostly spare capacity and a small header. A hash-shaped array (string or sparse keys) costs noticeably more per element. Measure with `memory_get_usage()` on your real data rather than assuming. ## Version history worth knowing - **PHP 8.0**: `SplFixedArray` became an `IteratorAggregate` instead of an `Iterator`; `foreach` gets a fresh iterator from `getIterator()`, so nested loops over one instance work correctly. Code that called `rewind()`, `current()` or `next()` on it directly broke. - **PHP 8.1**: `json_encode()` encodes it like an array. - **PHP 8.4**: out-of-bounds access throws `OutOfBoundsException` instead of `RuntimeException`; since the new class extends the old one, existing `catch (RuntimeException $e)` blocks still work. `__wakeup()` was deprecated in favour of `__serialize()`/`__unserialize()`. - **PHP 8.5**: faster dimension access and methods. ## Iterating and converting - `foreach` over an `SplFixedArray` yields every slot, including the `null` ones you never wrote, with integer keys from `0`. - `toArray()` returns a list of the same size, and `jsonSerialize()` is an alias of it, which is why JSON output looks like an array. - `getSize()` and `count()` both report the slot count, not the number of non-null values. ## When it is worth it - A **large numeric buffer of known size** in a CLI job or long-running worker: a sample window, a lookup table indexed `0..n`, a grid. - Code where an **out-of-range index is a bug** you want to surface immediately. It is not worth it for everyday application data: request payloads, rows from a database, anything with string keys, or anything you will filter, sort or map. There the plain array's functions and value semantics are worth far more than a few kilobytes, and the conversion cost of `toArray()` eats the gain.
- What changed in PHP 8.0 that made nested foreach loops over one SplFixedArray safe?Before 8.0, `SplFixedArray` implemented `Iterator`, so the instance itself held the loop position and nested loops interfered. Since 8.0 it implements `IteratorAggregate`: each `foreach` calls `getIterator()` and gets its own cursor. Code that called `current()` or `next()` on the object directly had to switch to `getIterator()`.
- Does catching RuntimeException still work for SplFixedArray index errors in PHP 8.5?Yes. Since PHP 8.4 out-of-range access throws `OutOfBoundsException`, which extends `RuntimeException`, so an older `catch (RuntimeException $e)` still catches it. New code can catch the narrower class.
saying these in an interview costs you the question
- SplFixedArray always uses far less memory than any array
- $fixed[] = $value appends and grows the SplFixedArray
- array_map() and sort() accept an SplFixedArray directly
- Passing an SplFixedArray to a function copies it like an array
- Out-of-range reads return null with a warning