Signature
array_is_list(array $array): boolPurpose
PHP arrays are ordered maps, so one array type covers both sequences and dictionaries. array_is_list() tells you which shape you have. It returns true when the keys are exactly the integers 0 to count($array) - 1, in that order. This is useful before encoding data, validating input that should be a sequence, or deciding whether an array can be treated like a plain list.
The function is available since PHP 8.1.0 and works the same way in PHP 8.4.
Signature
Parameters and defaults
$array: the array to inspect. It is required and has no default value.
Only the keys matter. The values can be of any type, including null, objects or other arrays.
Return value and failure cases
The function returns true if the array is a list and false otherwise. An empty array counts as a list, so array_is_list([]) is true.
There is no error return value. The parameter is typed as array, so passing something else, such as a string or null, throws a TypeError. Check the type first if the input is untrusted.
Example 1: basic checks
This example covers the most common results. An empty array and a normally built array are lists. An explicit 0 key followed by an automatic key is also a list. An array that starts at 1 is not.
$checks = [
'empty' => array_is_list([]),
'simple' => array_is_list(['apple', 2, 3]),
'explicit zero' => array_is_list([0 => 'apple', 'orange']),
'starts at one' => array_is_list([1 => 'apple', 'orange']),
];
echo json_encode($checks, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"empty":true,"simple":true,"explicit zero":true,"starts at one":false}
Example 2: order, names and gaps
A list needs consecutive integer keys in the correct order. Keys can fail in three ways: they are out of order, a key is a string name, or there is a gap.
$cases = [
'reversed keys' => [1 => 'apple', 0 => 'orange'],
'string key' => [0 => 'apple', 'foo' => 'bar'],
'gap' => [0 => 'apple', 2 => 'bar'],
];
foreach ($cases as $name => $value) {
echo $name, ': ', array_is_list($value) ? 'list' : 'not list', "\n";
}reversed keys: not list string key: not list gap: not list
The array with keys 1 then 0 contains the right key set, but the order is wrong. This is why the function checks position as well as key values.
Example 3: filtering breaks the list
array_filter() keeps the original keys of the items it retains. After filtering, the result may no longer be a list. Calling array_values() renumbers the keys.
$numbers = [10, 15, 20, 25];
$even = array_filter($numbers, fn(int $n): bool => $n % 2 === 0);
$reindexed = array_values($even);
echo json_encode([
'filteredIsList' => array_is_list($even),
'filteredJson' => $even,
'reindexedIsList' => array_is_list($reindexed),
'reindexedJson' => $reindexed,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"filteredIsList":false,"filteredJson":{"0":10,"2":20},"reindexedIsList":true,"reindexedJson":[10,20]}
The filtered array keeps keys 0 and 2, so it is not a list and encodes as a JSON object. The reindexed array encodes as a JSON array.
Edge cases
- Empty arrays return
true. - Numeric string keys such as
'0'and'1'are converted to integer keys by PHP when the array is created, so['0' => 'a', '1' => 'b']is a list. - Values are ignored.
[null, null]is a list, and so is[[1], ['x' => 2]]. The function does not look inside nested arrays. - Removing items with
unset()can leave a gap. Unsetting the last element keeps the array a list, but unsetting an earlier one does not. - Adding with
[]appends using the next integer key, so it keeps a list as a list only when the existing keys already form one.
Common mistakes
- Assuming
array_filter()returns a list. It preserves keys. Reindex witharray_values()when you need a sequence. - Treating it as a check for numeric keys only. Keys such as
[3 => 'a', 4 => 'b']are integers, but the array is not a list because it does not start at0. - Expecting it to validate values. The function says nothing about types or contents.
- Passing non-array input. A
TypeErroris thrown, so validate request data or decoded input before calling it. - Using it to detect an associative array. An array that is not a list is not necessarily a clean dictionary. It might have gaps, a different start or mixed keys.
Related functions
array_values()returns the values with fresh keys0, 1, 2, ..., which is the usual way to turn a non-list into a list.array_keys()returns the keys, which is useful when you need to see why a check failed.array_filter()andarray_slice()can change keys, so check afterward if the list shape matters.json_encode()outputs lists as JSON arrays and other arrays as JSON objects.
Recap
array_is_list() answers one question: do the keys run from 0 to count - 1 in order? It returns true for empty arrays, ignores values, and returns false for gaps, wrong order, non-zero starts or string keys. Pair it with array_values() when you need to normalize an array into a list.
Tested examples
$checks = [
'empty' => array_is_list([]),
'simple' => array_is_list(['apple', 2, 3]),
'explicit zero' => array_is_list([0 => 'apple', 'orange']),
'starts at one' => array_is_list([1 => 'apple', 'orange']),
];
echo json_encode($checks, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"empty":true,"simple":true,"explicit zero":true,"starts at one":false}
$cases = [
'reversed keys' => [1 => 'apple', 0 => 'orange'],
'string key' => [0 => 'apple', 'foo' => 'bar'],
'gap' => [0 => 'apple', 2 => 'bar'],
];
foreach ($cases as $name => $value) {
echo $name, ': ', array_is_list($value) ? 'list' : 'not list', "\n";
}reversed keys: not list string key: not list gap: not list
$numbers = [10, 15, 20, 25];
$even = array_filter($numbers, fn(int $n): bool => $n % 2 === 0);
$reindexed = array_values($even);
echo json_encode([
'filteredIsList' => array_is_list($even),
'filteredJson' => $even,
'reindexedIsList' => array_is_list($reindexed),
'reindexedJson' => $reindexed,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"filteredIsList":false,"filteredJson":{"0":10,"2":20},"reindexedIsList":true,"reindexedJson":[10,20]}