In PHP, which keys survive array_map() and array_filter(), and how do you filter by key with ARRAY_FILTER_USE_KEY?
answer
- array_filter keeps keys, leaves gaps
- array_values() after filtering a list
- array_map keeps keys for one array only
- USE_KEY passes the key, USE_BOTH value then key
- no callback drops every empty value, "0" too
basics
~10 sarray_filter() keeps the original keys, so a filtered list has gaps until array_values(); array_map() keeps keys only when given exactly one array. ARRAY_FILTER_USE_KEY passes each key to the callback, ARRAY_FILTER_USE_BOTH passes value then key.
solid answer
~40 s`array_filter($array, $callback, $mode)` returns the elements whose callback result is truthy and **preserves their keys**, so filtering `[0 => 'a', 1 => 'b', 2 => 'c']` down to `a` and `c` leaves keys 0 and 2; wrap it in `array_values()` when you need a list again. By default the callback receives the value; `ARRAY_FILTER_USE_KEY` passes only the key and `ARRAY_FILTER_USE_BOTH` passes the value and then the key. Without a callback it drops every empty entry: `false`, `0`, `0.0`, `''`, `'0'`, `null` and `[]`. `array_map($callback, $array)` with a **single** array keeps that array's keys, string or integer; with **two or more** arrays it returns a fresh list numbered from 0, and a `null` callback zips them. The callback never receives the key, so key-aware mapping needs `array_keys()` as a second array or a `foreach`.
code
php · 13 lines<?php
$qty = ['sourdough' => 2, 'eclair' => 0, 'rye' => 1];
print_r(array_filter($qty)); // sourdough => 2, rye => 1 (0 dropped)
print_r(array_filter($qty, fn ($k) => $k !== 'rye', ARRAY_FILTER_USE_KEY));
print_r(array_filter($qty, fn ($v, $k) => $v > 0 && $k[0] === 's', ARRAY_FILTER_USE_BOTH));
$list = array_filter(['a', 'b', 'c'], fn ($v) => $v !== 'b');
var_dump(array_keys($list)); // [0, 2]: gap kept
var_dump(array_keys(array_values($list))); // [0, 1]
print_r(array_map(fn ($n) => $n * 2, $qty)); // keys kept: one array
print_r(array_map(fn ($n, $k) => "$k:$n", $qty, array_keys($qty))); // keys 0, 1, 2go deeper
Recall that array_filter() keeps the original keys, leaving gaps, and that array_values() re-indexes the result into a list.
Explain the three array_filter() modes, the empty-value rule without a callback, and why array_map() keeps keys only with a single input array.
Spot chains that break list shape before json_encode() or drop legitimate zeros, and choose a foreach when both keys and values must drive the output.
Decide when functional array chains stay readable for a team and when explicit loops or typed collections communicate key handling more clearly.
## Why keys are the interview question `array_map()` and `array_filter()` look like the familiar map and filter operations, but PHP arrays are ordered maps, so each function has to decide what happens to the keys. Getting that wrong produces gaps in lists, lost string keys, or JSON that changes shape. Interviewers ask precisely because the value-level behaviour is easy and the key-level behaviour is not. ## array_filter(): keys are preserved `array_filter(array $array, ?callable $callback = null, int $mode = 0): array` keeps the elements for which the callback returns a truthy value and keeps them **under their original keys**: ```php $orders = ['sourdough', 'eclair', 'rye']; $breads = array_filter($orders, fn ($o) => $o !== 'eclair'); // [0 => 'sourdough', 2 => 'rye'] ``` The gap at key 1 matters later: an index loop reads a missing key, and `json_encode()` turns the array into an object because it is no longer a list. `array_values($breads)` restores keys 0 and 1. ### The mode argument | `$mode` | Callback receives | Typical use | |---|---|---| | `0` (default) | `$value` | keep values that pass a test | | `ARRAY_FILTER_USE_KEY` | `$key` | keep an allow-list of keys, drop internal fields | | `ARRAY_FILTER_USE_BOTH` | `$value, $key` | rules that need both, such as a key prefix and a non-empty value | The `ARRAY_FILTER_USE_KEY` mode is the common way to whitelist fields from an input array: ```php $allowed = ['name', 'address', 'slot']; $clean = array_filter($input, fn ($k) => in_array($k, $allowed, true), ARRAY_FILTER_USE_KEY); ``` ### No callback Called with no callback, `array_filter()` removes every entry that is **empty** in PHP's sense: `false`, `0`, `0.0`, `''`, `'0'`, `null` and `[]`. That is convenient for stripping blanks from form input and dangerous for data where `0` or `'0'` is a legitimate value, such as a quantity of zero or a postcode fragment. ## array_map(): keys depend on how many arrays you pass `array_map(?callable $callback, array $array, array ...$arrays): array` applies the callback to each value: 1. **One array**: the result keeps the input's keys, string and integer alike. Mapping `['ana' => 3, 'ben' => 5]` with `fn ($n) => $n * 2` gives `['ana' => 6, 'ben' => 10]`. 2. **Two or more arrays**: the callback receives one value from each array per position, and the result is a new list numbered from 0; the input keys are discarded. 3. **`null` callback with several arrays**: the result is a zip, a list of small arrays pairing up elements by position. The callback never receives the key. Two workarounds are common, each with a trade-off: - `array_map($fn, $array, array_keys($array))` passes the key as a second argument, but because two arrays are passed the result is renumbered, so the keys are lost from the output. - A `foreach ($array as $key => $value)` that builds the result explicitly keeps full control, and is often the clearest option. ## Putting them together A typical chain in the bakery-delivery app: keep today's paid orders, then map them to display lines. - `array_filter()` keeps the original order IDs as keys, which is useful if the IDs are the keys. - `array_map()` with one array keeps those keys too. - If the output must be a JSON list, finish with `array_values()`. ## Summary rules - `array_filter()` always preserves keys; re-index with `array_values()` when a list is required. - `array_map()` preserves keys only with exactly one input array. - `ARRAY_FILTER_USE_KEY` and `ARRAY_FILTER_USE_BOTH` are the only ways to see keys in `array_filter()`; note the value-then-key order for `USE_BOTH`. - A missing callback means "drop empty values", including `'0'`.
- A filtered list is sent to the browser with json_encode() and suddenly arrives as an object. Why?`array_filter()` kept the original integer keys, so removing an element left a gap and the array is no longer a list. `json_encode()` encodes non-lists as JSON objects. Wrap the filter in `array_values()` before encoding.
- Why can array_filter() without a callback silently lose data?With no callback it removes every empty value, which includes `0`, `0.0`, `'0'` and `''` as well as `null` and `false`. A quantity of zero or a code stored as `'0'` disappears. Pass an explicit callback such as `fn ($v) => $v !== null` to state what should be removed.
saying these in an interview costs you the question
- array_filter() re-indexes the result from 0 automatically.
- array_map() always returns a list numbered from 0.
- ARRAY_FILTER_USE_BOTH passes the key first and the value second.
- array_filter() without a callback removes only null values.
- array_map() passes each element's key as the callback's second argument.