Как проверить, ассоциативный массив или последовательный в PHP: разбираем топ ошибок
Вы когда-нибудь писали foreach и получали не то, что ожидали? А может, передавали массив в функцию, которая ждала список, а получала ассоциативный массив с ключами-строками? Если да — вы не одиноки. Вопрос «How to check if PHP array is associative or sequential?» входит в топ самых популярных на Stack Overflow с тысячами просмотров. И это не случайно: путаница между типами массивов — одна из главных ловушек для PHP-разработчиков.
В этой статье мы разберём, чем отличаются ассоциативные и последовательные (sequential) массивы, покажем частые ошибки и дадим рабочие решения. Поехали!
Что такое последовательный и ассоциативный массив?
В PHP нет строгого разделения на «списки» и «словари», как в Python или JavaScript. Один тип — array — может быть и тем, и другим. Но на практике важно понимать разницу:
- Последовательный (sequential) массив — ключи идут по порядку: 0, 1, 2, 3... без пропусков. Пример:
['яблоко', 'груша', 'вишня']. - Ассоциативный массив — ключи — строки или числа не по порядку. Пример:
['name' => 'Иван', 'age' => 30].
Казалось бы, всё просто. Но на практике разработчики часто ошибаются, пытаясь определить тип массива вручную. Давайте разберём самые популярные ошибки.
Топ ошибка №1: Использовать array_keys() и сравнивать с range
Один из самых распространённых подходов — взять ключи массива, сгенерировать последовательность от 0 до count($array)-1 и сравнить. Выглядит логично, но есть нюансы.
// Пример ошибочного подхода
function isSequential($arr) {
return array_keys($arr) === range(0, count($arr) - 1);
}
$test = ['a', 'b', 'c'];
var_dump(isSequential($test)); // true — верно
$test2 = ['x' => 1, 'y' => 2];
var_dump(isSequential($test2)); // false — верно
$test3 = [0 => 'a', 2 => 'b'];
var_dump(isSequential($test3)); // false — верно
$test4 = ['0' => 'a', '1' => 'b'];
var_dump(isSequential($test4)); // ???
Проблема в том, что PHP автоматически приводит строковые ключи к целым числам, если они выглядят как числа. ['0' => 'a', '1' => 'b'] — это на самом деле последовательный массив, но наша функция может дать неожиданный результат из-за строгого сравнения (===).
Вывод: такой подход работает, но только если вы уверены в типах ключей. Для продакшена лучше использовать более надёжные методы.
Топ ошибка №2: Проверять только первый ключ
Некоторые разработчики думают: «Если первый ключ — 0, то массив последовательный». Это опасное заблуждение.
function isSequentialByFirstKey($arr) {
if (empty($arr)) return true;
return array_key_first($arr) === 0;
}
$bad = [0 => 'a', 'name' => 'Иван'];
var_dump(isSequentialByFirstKey($bad)); // true — а должно быть false!
Первый ключ — 0, но массив явно ассоциативный. Такая проверка пропустит смешанные массивы, которые часто встречаются в реальных проектах.
Вывод: никогда не судите о массиве по первому элементу. Проверяйте все ключи.
Топ ошибка №3: Игнорировать пустые массивы
Пустой массив [] — одновременно и последовательный, и ассоциативный? С точки зрения PHP — да. Но некоторые функции дают сбой.
function isAssociative($arr) {
return count(array_filter(array_keys($arr), 'is_string')) > 0;
}
var_dump(isAssociative([])); // false — пустой массив не ассоциативный
var_dump(isAssociative([1, 2, 3])); // false — верно
Вроде бы логично, но если вы ожидаете, что функция вернёт true для пустого массива (как для ассоциативного), вы ошибаетесь. Пустой массив — это частный случай, который нужно обрабатывать отдельно, в зависимости от бизнес-логики.
Вывод: всегда явно проверяйте, что делать с пустыми массивами. Не полагайтесь на «умолчания».
Лучшее решение: используйте встроенные функции PHP
Начиная с PHP 8.1, у нас есть встроенная функция array_is_list(). Она делает именно то, что нужно: проверяет, является ли массив списком (последовательным, начиная с 0).
// PHP 8.1+
$seq = ['a', 'b', 'c'];
$assoc = ['name' => 'Иван', 'age' => 30];
$mixed = [0 => 'a', 2 => 'b'];
$empty = [];
var_dump(array_is_list($seq)); // true
var_dump(array_is_list($assoc)); // false
var_dump(array_is_list($mixed)); // false (есть пропуск)
var_dump(array_is_list($empty)); // true (пустой список — тоже список)
Если вы используете PHP 8.1 или выше — это ваш выбор. Функция быстрая, протестированная и понятная.
А что если у вас PHP 7.x или 8.0?
Не беда. Вот универсальная функция, которая работает на всех версиях:
function isSequentialArray(array $arr): bool {
if (empty($arr)) {
return true; // или false — зависит от вашей логики
}
return array_keys($arr) === range(0, count($arr) - 1);
}
// Альтернатива с array_values
function isAssociativeArray(array $arr): bool {
if (empty($arr)) {
return false;
}
return array_keys($arr) !== range(0, count($arr) - 1);
}
Этот метод проверяет, что ключи — это последовательность 0, 1, 2... без пропусков и без строковых ключей. Он надёжен и прост.
Как избежать ошибок на практике: 3 совета
1. Всегда документируйте ожидаемый тип массива
Если ваша функция ожидает только последовательный массив, напишите это в PHPDoc:
/**
* @param list<string> $items Только последовательный массив строк
*/
function processItems(array $items): void {
// ...
}
Используйте list<Type> для последовательных массивов и array<string, Type> для ассоциативных. Это поможет и вам, и другим разработчикам.
2. Проверяйте в начале функции
Добавьте защитную проверку в начале важных функций:
function calculate(array $data): float