In PHP 8.5, what does a destructuring assignment like [$lat, $lng] = $point do when $point lacks those keys or is not an array?
answer
- the code keeps running with null
- Undefined array key is an E_WARNING
- null on the right: silent nulls
- int, string, bool warn since 8.5
- plain object throws Error
basics
~20 sMissing keys raise an E_WARNING and assign null. A null right-hand side assigns null silently; since PHP 8.5 an int, float, string or bool does the same but warns. A plain object throws an Error unless it implements ArrayAccess.
solid answer
~40 sDestructuring never checks the whole shape; it looks up each key separately. A key that is missing raises `E_WARNING` "Undefined array key" and the variable gets `null`, so an associative `['lat' => …]` array under a positional pattern produces two warnings and two nulls. If the right-hand side is `null`, every variable becomes `null` with no diagnostic at all. PHP 8.5 added a warning for other scalars: destructuring an `int`, `float`, `string` or `bool` now emits "Cannot use int as array" (and so on) per variable, where earlier versions were silent. An object works only if it implements `ArrayAccess`; otherwise PHP throws an `Error`. Because most of these cases continue with `null`, validate a payload's shape before unpacking it.
code
php · 17 lines<?php
declare(strict_types=1);
[$lat, $lng] = explode(',', '46.5580');
// Warning: Undefined array key 1 -> $lng is null
[$lat, $lng] = ['lat' => 46.558, 'lng' => 7.981];
// Warning: Undefined array key 0, then key 1 -> both null
[$lat, $lng] = null; // both null, no diagnostic
[$lat, $lng] = false; // PHP 8.5: Warning: Cannot use bool as array (twice)
try {
[$lat, $lng] = new stdClass();
} catch (Error $e) {
echo $e->getMessage(), PHP_EOL; // Cannot use object of type stdClass as array
}go deeper
Recall that a missing key gives null and a warning, and that a positional pattern needs keys 0 and 1 to exist.
Walk through each right-hand side: short list, associative array, null, other scalars, plain object, ArrayAccess, and say which warn, which stay silent and which throw.
Validate payload shape before unpacking, turn warnings into test failures, and flag the null and false cases in review, knowing the false case only warns from PHP 8.5.
Set a boundary policy: external data is validated and mapped into typed objects once, so destructuring's silent-null behaviour never reaches business logic.
## Destructuring is a series of lookups A pattern like `[$lat, $lng] = $point;` is compiled into one read per variable: read key `0` into `$lat`, read key `1` into `$lng`. There is no step that checks the array has exactly the expected shape first. Each read succeeds or fails on its own, and most failures produce `null` plus, at most, a warning. Knowing which case gives which result is what separates a quiet bug from a loud one. ## Case by case | Right-hand side | Result in PHP 8.5 | Diagnostic | |---|---|---| | `[46.55, 7.98]` | both assigned | none | | `[46.55]` (too short) | `$lng = null` | `E_WARNING` Undefined array key 1 | | `['lat' => 46.55, 'lng' => 7.98]` | both `null` | two Undefined array key warnings | | `null` | both `null` | none | | `5`, `'46.55,7.98'`, `false` | both `null` | `E_WARNING` "Cannot use int as array" (or string, bool), once per variable | | a plain object (`stdClass`) | nothing assigned | `Error`: Cannot use object of type stdClass as array | | an `ArrayAccess` object | `offsetGet(0)`, `offsetGet(1)` | whatever the object does | Two lines in that table changed in recent releases. Missing keys were `E_NOTICE` before PHP 8.0 and are `E_WARNING` since. Scalars other than `null` were destructured silently into `null` before PHP 8.5; the 8.5 release added the warning. ## Where these cases come from in real code A hiking-route API gives each point as `"46.5580,7.9812"` in one field and as `{"lat": …, "lng": …}` in another. Typical failure paths: 1. **A short list.** `[$lat, $lng] = explode(',', $field);` on a field that contains only `"46.5580"` gives `$lng = null` and one warning. 2. **Wrong pattern for the shape.** A decoded JSON object becomes an associative array, so a positional pattern reads nothing. 3. **A failed call returning `false`.** Functions typed `array|false`, such as `getimagesize()`, return `false` on failure. In PHP 8.5 destructuring that result warns "Cannot use bool as array"; in older versions it was silent. 4. **A `null` result.** A decoder that returns `null` for invalid input leads to silent nulls, even in PHP 8.5, because `null` is deliberately exempt from the new warning. ## Things the compiler rejects outright Some shape assumptions cannot be written at all: - `[$head, ...$tail] = $items;` is a compile-time fatal error, "Spread operator is not supported in assignments". There is no rest element; use `array_slice()` for the tail. - Patterns have no default-value syntax. Defaults come from the source array (merge them in before unpacking) or from `??` applied afterwards. ## Making mismatches loud Because the common outcome is `null` with at most a warning, defensive code checks shape at the boundary: - **Check before unpacking.** `is_array($point)` and `count($point) === 2`, or `array_key_exists('lat', $point)`, before the destructuring line. - **Prefer keyed patterns for payloads.** `['lat' => $lat, 'lng' => $lng]` documents the contract and fails per missing field, not by silently reading the wrong position. - **Convert warnings into exceptions** in development and tests, so an `Undefined array key` fails the test instead of scrolling past in a log. - **Map to a typed object once.** A small class with `float $lat` and `float $lng` properties rejects `null` through its type declarations, turning the silent case into a `TypeError` at the edge. ## Reading the diagnostics The messages point straight at the case you hit: - **"Undefined array key 1"** — the array exists but lacks that key: a short list or a positional pattern on associative data. - **"Cannot use bool as array"** (or `int`, `float`, `string`) — the value was not an array at all; since PHP 8.5 this is reported once per variable in the pattern. - **"Cannot use object of type X as array"** — an `Error`, so execution stops unless caught. - **Nothing at all** — the value was `null`, or everything matched. Only a check you write yourself tells these two apart. ## Summary A destructuring assignment trusts the data. In PHP 8.5 it tells you about most mismatches with a warning, stays silent for `null`, and throws only for objects that cannot act as arrays. Treat each of these as a validation gap, not as a language guarantee.
- Why is null exempt from the PHP 8.5 warning while false is not?The PHP 8.5 change covers non-array values other than `null`, so destructuring `null` stays silent exactly as before. Other scalars, including the `false` that many functions return on failure, usually mean the code expected an array and got something else, so they now warn once per variable.
- How do you give a destructured variable a default when the key is missing?Patterns have no default syntax. Apply `??` after unpacking (`$lng ??= 0.0;`, which still leaves the warning) or, better, merge defaults into the source first, for example `['lat' => $lat, 'lng' => $lng] = $point + ['lat' => 0.0, 'lng' => 0.0];`, so every key exists.
saying these in an interview costs you the question
- Destructuring throws an exception when a key is missing
- Destructuring null raises a warning in PHP 8.5
- A positional pattern reads associative arrays in insertion order
- Destructuring a string splits it into characters
- [$head, ...$tail] = $items is valid PHP 8 syntax