PHP Array Destructuring (list())
Array destructuring lets you pull values out of an array and drop them straight into individual variables, in a single line, instead of writing one assignment per index or key. In PHP this is done with the list() language construct or its modern shorthand, the square-bracket [] syntax. It is one of the most useful shortcuts for working with arrays returned from functions, database rows, and configuration data, and understanding exactly how it maps array elements to variables will save you from a whole class of subtle bugs.
Overview / How it works
list() is not a real function — it is a language construct that the Zend Engine understands at compile time, much like echo or isset(). When PHP compiles an expression like list($a, $b) = $array;, it does not call anything; instead it generates a sequence of opcodes that fetch $array[0] and $array[1] and assign them directly to $a and $b. Since PHP 7.1, you can write the same thing with the short array syntax, [$a, $b] = $array;, which compiles to identical opcodes — it is purely a syntactic alternative, not a different feature. Most modern PHP code prefers the short syntax because it mirrors how the array itself was likely created.
Destructuring works with both plain indexed arrays (unpacking by position, starting at key 0) and associative arrays (unpacking by explicit key, added in PHP 7.1). You can skip elements you don’t need by leaving an empty slot between commas, and you can destructure nested arrays by nesting [] patterns to match the array’s actual shape. Because it only understands arrays, destructuring will not work on plain objects or on the individual items of a Generator as a whole — though it works perfectly on each array yielded inside a foreach loop, which is one of its most common uses: unpacking rows of tabular data (like `id, name, email` tuples) as you iterate.
Syntax
list($var1, $var2, ...) = $array;
[$var1, $var2, ...] = $array;
// Keyed form
['key1' => $var1, 'key2' => $var2] = $array;
// Skipping elements
[, $second, , $fourth] = $array;
// Nested
[$a, [$b, $c]] = [1, [2, 3]];
| Part | Meaning |
|---|---|
list(...) / [...] |
The destructuring pattern on the left-hand side; both forms are interchangeable |
Empty slot (, with nothing between) |
Skips the value at that position without creating a variable |
'key' => $var |
Pulls the value at that specific array key, regardless of its position |
Nested [$x, $y] |
Destructures a sub-array found at that position or key |
$array |
The right-hand side; must evaluate to an array (or be an array-shaped literal) |
Examples
Example 1: Basic positional destructuring
<?php
$coordinates = [12.5, 45.2, 100.0];
[$x, $y, $z] = $coordinates;
echo "X: $x\n";
echo "Y: $y\n";
echo "Z: $z\n";
Output:
X: 12.5
Y: 45.2
Z: 100
Each variable is assigned the value at the matching numeric index: $x gets index 0, $y gets index 1, and so on. Notice that 100.0 prints as 100 because PHP drops an unnecessary trailing .0 when converting a float to a string.
Example 2: Skipping elements and keyed destructuring
<?php
$row = [7, 'red', 'apple'];
list(, $color, $fruit) = $row;
echo "Color: $color\n";
echo "Fruit: $fruit\n";
$user = ['id' => 42, 'name' => 'Maria', 'email' => 'maria@example.com', 'role' => 'admin'];
['name' => $name, 'role' => $role] = $user;
echo "Name: $name\n";
echo "Role: $role\n";
Output:
Color: red
Fruit: apple
Name: Maria
Role: admin
The empty slot before $color skips the numeric ID at index 0 entirely, so no variable is wasted on a value you don’t need. The second half shows keyed destructuring: because $user is associative, we pull values out by key name rather than position, which also means the order of keys in the pattern doesn’t have to match their order in the array.
Example 3: Nested destructuring inside a foreach loop
<?php
$products = [
['Laptop', 999.99, ['brand' => 'TechCo', 'stock' => 5]],
['Mouse', 19.99, ['brand' => 'ClickIt', 'stock' => 150]],
];
foreach ($products as [$productName, $price, ['brand' => $brand, 'stock' => $stock]]) {
echo "{$productName} by {$brand}: \${$price} ({$stock} in stock)\n";
}
Output:
Laptop by TechCo: $999.99 (5 in stock)
Mouse by ClickIt: $19.99 (150 in stock)
This is where destructuring really shines: instead of writing $product[0], $product[1], and $product[2]['brand'] inside the loop body, the pattern in the foreach header does all the unpacking up front, including reaching one level deeper into the nested brand/stock array. The nested pattern’s shape must mirror the array’s actual shape at that position.
Under the hood: step by step
When PHP evaluates [$a, $b] = [$b, $a];, it first fully evaluates the entire right-hand side into a temporary array, and only afterward performs the assignments to the left-hand variables one at a time. This ordering is what makes the classic swap trick work without a temporary variable:
<?php
$a = 1;
$b = 2;
[$a, $b] = [$b, $a];
echo "a=$a b=$b\n";
Output:
a=2 b=1
Step by step, PHP: (1) builds the temporary array [$b, $a] using the original values of $b and $a (2 and 1); (2) assigns index 0 of that temporary array to $a, making $a = 2; (3) assigns index 1 to $b, making $b = 1. Because the right-hand side is fully materialized before any assignment happens, there is no risk of an already-overwritten variable leaking into a later assignment in the same statement.
Common Mistakes
Mistake 1: Using positional destructuring on an associative array. If you write [$name, $age] = $data; but $data only has string keys like 'name' and 'age', PHP looks for numeric keys 0 and 1, which don’t exist. The result is null in both variables (with an “undefined array key” warning at runtime), not the values you expected.
$data = ['name' => 'Alice', 'age' => 30];
[$name, $age] = $data;
echo $name;
The fix is to destructure by the actual keys the array uses:
<?php
$data = ['name' => 'Alice', 'age' => 30];
['name' => $name, 'age' => $age] = $data;
echo "$name is $age years old\n";
Mistake 2: Destructuring a value that might not be an array. A function that can return null on failure is a common source of this bug. Destructuring its result without checking first causes a runtime warning and leaves every target variable as null, which then silently propagates through the rest of the script.
<?php
function findUser(int $id): ?array
{
return null;
}
[$name, $email] = findUser(99);
echo $name ?? 'no name';
Guard against this by checking the return value before destructuring:
<?php
function findUser(int $id): ?array
{
return null;
}
$user = findUser(99);
if ($user !== null) {
[$name, $email] = $user;
} else {
[$name, $email] = [null, null];
}
echo $name ?? 'no name';
Best Practices
- Prefer the short
[]syntax overlist()in new code; it reads more consistently with array literals and is the more common modern style. - Always match the destructuring pattern’s shape (positional vs. keyed, and nesting depth) to the array’s real structure — mismatches fail silently with
nullvalues rather than throwing an error. - Use keyed destructuring for associative arrays such as decoded JSON or config arrays, since it stays correct even if key order changes later.
- Check that a value is actually an array (not
nullor a scalar) before destructuring the result of a function call. - Skip unwanted positions with empty slots (
[, $second]) instead of assigning them to a throwaway variable you never use. - Reach for destructuring inside
foreachwhenever you’re iterating over a list of tuples or rows — it removes repetitive index lookups from the loop body. - Keep nested destructuring patterns shallow (one or two levels); beyond that, plain variable assignments are usually easier to read.
Practice Exercises
Exercise 1: Given $point = ['x' => 5, 'y' => 12];, use keyed destructuring to extract $x and $y, then print the distance from the origin using sqrt($x ** 2 + $y ** 2). Expected output: 13.
Exercise 2: Given $pairs = [[1, 2], [3, 4], [5, 6]];, use a foreach loop with destructuring in the loop header to print the sum of each pair on its own line. Expected output: three lines reading 3, 7, and 11.
Exercise 3: Starting from $a = 1; $b = 2; $c = 3;, use a single destructuring assignment to rotate the values so that afterward $a is 2, $b is 3, and $c is 1. Hint: build the right-hand side as an array of the other two variables plus the first.
Summary
list()and the short[]syntax are two interchangeable ways to destructure an array into individual variables; both compile to the same underlying opcodes.- Destructuring can be positional (by index), keyed (by array key, since PHP 7.1), or nested to match arrays inside arrays.
- Empty slots between commas let you skip elements you don’t need without creating extra variables.
- The right-hand side is fully evaluated before any assignment happens, which is what makes the no-temporary-variable swap trick work.
- Mismatching the pattern’s shape against the array’s real structure is the most common bug — it produces silent
nullvalues and warnings rather than a fatal error. - Destructuring is especially powerful inside
foreachloops for cleanly unpacking rows or tuples on each iteration.
