Question
In PHP, arrays can contain either numeric or string keys, and there is no separate built-in array type for lists versus associative maps in older PHP versions. What is an efficient way to check whether an array behaves like a list—that is, whether it contains only numeric keys starting at 0 in order?
For example, how can I distinguish between these two arrays?
$sequentialArray = [
'apple', 'orange', 'tomato', 'carrot'
];
$assocArray = [
'fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot'
];
Short Answer
By the end of this page, you will understand how PHP array keys work, how to tell whether an array is sequential or associative, and which approaches are best in modern and older PHP versions. You will also see practical examples, common mistakes, and how this check is used in real applications.
Concept
PHP uses one array type for both:
- Lists: values stored with numeric keys in order, usually starting at
0 - Associative arrays: values stored with named keys
That means this is valid in PHP:
$items = ['a', 'b', 'c'];
and so is this:
$items = ['first' => 'a', 'second' => 'b'];
Internally, both are arrays.
The difference is in the keys.
A sequential array (often called a list) usually has keys like this:
[0, 1, 2, 3]
An associative array has keys like this:
['name', 'email', 'role']
or even numeric keys that are not a continuous sequence:
[1 => 'apple', 3 => 'orange']
That last example is important: even though the keys are numbers, it is not a proper list if your rule is “numeric keys starting at 0 with no gaps.”
This matters because real programs often need to know whether data should be processed as:
- a collection of items, or
- a key/value object-like structure
For example:
- JSON encoding may produce different structures
- validation may differ for lists and maps
- APIs often expect one format or the other
- loops and transformations may behave differently depending on the key shape
In modern PHP, the clearest built-in solution is:
array_is_list($array)
This was introduced in PHP 8.1 and checks exactly whether the array keys are 0 through n-1 in order.
Mental Model
Think of a PHP array like a set of labeled storage boxes.
- A sequential array is like boxes on a shelf labeled
0,1,2,3with no missing numbers. - An associative array is like boxes labeled
fruit1,fruit2,veg1,veg2.
If the labels are perfect shelf positions starting at 0, it is a list.
If the labels are custom names, or the numbers skip around, it is associative for practical purposes.
Another way to think about it:
- List = “a row of items”
- Associative array = “a lookup table”
Your check is really asking:
Are these values arranged in a clean row, or are they stored by custom labels?
Syntax and Examples
Modern PHP: array_is_list()
If you are using PHP 8.1 or later, use this:
$sequentialArray = ['apple', 'orange', 'tomato', 'carrot'];
$assocArray = [
'fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot'
];
var_dump(array_is_list($sequentialArray)); // true
var_dump(array_is_list($assocArray)); // false
This is the best option because it is:
- readable
- built into PHP
- designed for exactly this purpose
Older PHP versions
If array_is_list() is not available, a common approach is:
function is_list_array(array $array): bool
{
return array_keys($array) === range(0, count($array) - 1);
}
Example:
$sequentialArray = ['apple', 'orange', 'tomato', 'carrot'];
$assocArray = [
'fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot'
];
var_dump(is_list_array($sequentialArray)); // true
var_dump(is_list_array($assocArray)); // false
Why this works
array_keys($array)
returns the array's keys.
For a sequential array like:
['apple', 'orange', 'tomato']
PHP stores keys as:
[0, 1, 2]
Then this creates the expected list of keys:
range(0, count($array) - 1)
If both key lists match exactly, the array is sequential.
Handle the empty array correctly
A small edge case: range(0, -1) is not what you want for an empty array.
A safer version is:
function is_list_array(array $array): bool
{
if ($array === []) {
return true;
}
return array_keys($array) === range(0, count($array) - 1);
}
An empty array is usually considered a valid list because it has no invalid keys.
Example with non-sequential numeric keys
$array = [1 => 'apple', 2 => 'orange'];
var_dump(array_is_list($array)); // false in PHP 8.1+
Even though the keys are numeric, the array is not a list because it does not start at 0.
Step by Step Execution
Consider this function:
function is_list_array(array $array): bool
{
if ($array === []) {
return true;
}
return array_keys($array) === range(0, count($array) - 1);
}
$data = ['apple', 'orange', 'tomato'];
$result = is_list_array($data);
var_dump($result);
Here is what happens step by step:
-
$datais created:['apple', 'orange', 'tomato']PHP automatically gives it these keys:
[0, 1, 2] -
is_list_array($data)is called. -
The function checks:
$array === []This is
falsebecause the array is not empty. -
The function gets the keys:
array_keys($array)Result:
[0, 1, 2] -
The function builds the expected sequence:
range(0, count($array) - 1)count($array)is3, so this becomes:range(0, 2)Result:
[0, 1, 2] -
PHP compares both arrays with
===:[0, 1, 2] === [0, 1, 2]This is
true. -
The function returns
true, sovar_dump($result)prints:bool(true)
Now compare this with:
$data = [1 => 'apple', 2 => 'orange'];
array_keys($data)gives[1, 2]range(0, count($data) - 1)gives[0, 1]- These do not match
- The function returns
false
Real World Use Cases
1. Choosing how to encode data for JSON
When sending data to a frontend or API, you may need to know whether something should be treated like a list or an object-like map.
$data = ['apple', 'orange'];
This behaves like a collection of values.
But this:
$data = ['first' => 'apple', 'second' => 'orange'];
behaves more like labeled fields.
2. Validating API input
Suppose an endpoint expects a list of user IDs:
[12, 18, 25]
You may reject input like:
['admin' => 12, 'editor' => 18]
because it is not the expected shape.
3. Processing form or configuration data
Some configuration values are key/value pairs:
[
'host' => 'localhost',
'port' => 3306
]
Others are just lists:
['cache', 'queue', 'mail']
The check helps you decide how to loop over the data.
4. Data normalization
When importing CSV, JSON, or database results, you may receive inconsistent structures. Detecting whether an array is a list helps normalize the data before further processing.
5. Recursive data walkers
In utility functions that inspect nested arrays, developers often treat lists and associative arrays differently when formatting, validating, or transforming data.
Real Codebase Usage
In real projects, developers rarely check array type just for curiosity. They usually do it because the code must branch into different behavior.
Common patterns
Guard clauses
Reject invalid input early:
function processIds(array $ids): void
{
if (!array_is_list($ids)) {
throw new InvalidArgumentException('Expected a list of IDs.');
}
foreach ($ids as $id) {
// Process each ID
}
}
Validation
Frameworks and service classes often validate not just values, but also structure.
function validateTags(array $tags): bool
{
if (!array_is_list($tags)) {
return false;
}
foreach ($tags as $tag) {
if (!is_string($tag)) {
return false;
}
}
return true;
}
Recursive formatting or transformation
function describeArray(array $data): string
{
if (array_is_list($data)) {
return 'list';
}
return 'associative array';
}
Defensive coding with external data
Data from APIs, JSON, and user input may look similar but have different key structures. Developers often check list shape before using foreach assumptions or before mapping values.
Why readability matters
A custom function like is_list_array() is fine in older PHP versions, but in modern codebases array_is_list() is better because other developers immediately understand the intent.
Common Mistakes
1. Assuming numeric keys always mean a list
This is wrong:
$array = [2 => 'apple', 3 => 'orange'];
These are numeric keys, but it is not a sequential list starting at 0.
2. Forgetting gaps in keys
Broken assumption:
$array = [0 => 'apple', 2 => 'orange'];
This is not a list because key 1 is missing.
3. Using isset($array[0]) as the only test
Broken example:
function isListWrong(array $array): bool
{
return isset($array[0]);
}
Why it is wrong:
- it only checks one key
- it does not verify the rest of the keys
- it fails for empty arrays
4. Ignoring the empty array case
Broken version:
function is_list_array(array $array): bool
{
return array_keys($array) === range(0, count($array) - 1);
}
For an empty array, this can behave unexpectedly because range(0, -1) is not the intended comparison.
Safer version:
function is_list_array(array $array): bool
{
if ($array === []) {
return true;
}
return array_keys($array) === range(0, count($array) - 1);
}
5. Confusing insertion order with key sequence
An array can be added in order but still not be a proper list if keys were assigned manually.
$array = [];
$array[1] = 'apple';
$array[2] = 'orange';
This is ordered, but still not a list by the usual rule.
6. Using loose comparisons
Prefer strict comparison:
array_keys($array) === range(0, count($array) - 1)
instead of:
array_keys($array) == range(0, count($array) - 1)
Strict comparison avoids surprising type-related matches.
Comparisons
| Approach | PHP Version | Good For | Notes |
|---|---|---|---|
array_is_list($array) | 8.1+ | Modern projects | Best choice: built-in, readable, accurate |
array_keys($array) === range(0, count($array) - 1) | Older PHP | Compatibility | Common fallback, but handle empty arrays carefully |
| Loop through keys manually | Any | Performance-sensitive custom logic | More verbose, useful if you want full control |
isset($array[0]) | Any | Almost never sufficient | Not a real list check |
Associative vs sequential
| Type | Example | Is it a list? | Why |
|---|---|---|---|
| Sequential | ['a', 'b', 'c'] | Yes | Keys are 0, 1, 2 |
| Associative | ['x' => 'a', 'y' => 'b'] | No | Keys are strings |
| Numeric but shifted | [1 => 'a', 2 => 'b'] | No | Does not start at 0 |
| Numeric with gaps | [0 => 'a', 2 => 'b'] | No | Missing key 1 |
| Empty array | [] | Usually yes | No invalid keys exist |
array_is_list() vs custom helper
| Feature | array_is_list() | Custom helper |
|---|---|---|
| Readability | Excellent | Good if well named |
| Built-in | Yes | No |
| Works on older PHP | No | Yes |
| Maintenance | Low | Slightly higher |
| Best for new code | Yes | Only if needed for compatibility |
Cheat Sheet
Quick rule
A PHP array is a list if its keys are exactly:
0, 1, 2, ..., n-1
with no gaps and in order.
Best modern solution
array_is_list($array)
- Available in PHP 8.1+
- Returns
truefor sequential arrays - Returns
falsefor associative or non-sequential arrays
Older PHP fallback
function is_list_array(array $array): bool
{
if ($array === []) {
return true;
}
return array_keys($array) === range(0, count($array) - 1);
}
Examples
array_is_list(['a', 'b', 'c']); // true
array_is_list(['x' => 'a', 'y' => 'b']); // false
array_is_list([1 => 'a', 2 => 'b']); // false
array_is_list([0 => 'a', 2 => 'b']); // false
array_is_list([]); // true
Important edge cases
- Numeric keys are not enough
- Keys must start at
0 - Keys must be continuous
- Empty array is usually treated as a valid list
Avoid
isset($array[0])
This does not prove the array is a list.
Good use cases
- validating API input
- checking data structure shape
- branching between list logic and map logic
- preparing data for encoding or transformation
FAQ
How do I check if an array is associative in PHP?
A common approach is to check whether it is not a list:
$isAssociative = !array_is_list($array);
In older PHP versions, use a custom helper instead.
Is there a built-in PHP function for checking list arrays?
Yes. In PHP 8.1 and later, use:
array_is_list($array)
Are arrays with numeric keys always sequential?
No. Numeric keys like [1 => 'a', 2 => 'b'] are not sequential lists if they do not start at 0.
Does an empty array count as a list?
Usually yes. It contains no invalid keys, so it is generally treated as a valid empty list.
What is the difference between associative and sequential arrays in PHP?
A sequential array has keys 0 through n-1 in order. An associative array uses custom keys such as strings, or numeric keys that are not a continuous sequence.
Why does this matter when working with JSON or APIs?
Because your code may need to treat a collection of items differently from a key/value object structure. Validation and transformation often depend on that distinction.
What should I use in older PHP versions before 8.1?
Use a helper like this:
function is_list_array(array $array): bool
{
if ($array === []) {
return true;
}
return array_keys($array) === range(0, count($array) - 1);
}
Mini Project
Description
Build a small PHP utility that inspects several arrays and reports whether each one is a sequential list or an associative array. This is useful for understanding how PHP treats array keys and for practicing reusable helper functions that can be used in validation or data processing code.
Goal
Create a script that checks multiple arrays and prints whether each one is a list or associative.
Requirements
- Write a function that returns whether an array is a sequential list.
- Treat an empty array as a valid list.
- Test the function with at least four different arrays.
- Print a readable label for each test case.
- Include one example with numeric keys that are not sequential.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.