Как проверить, ассоциативный массив или нет в PHP: топ ошибок

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как проверить, ассоциативный массив или последовательный в 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                

Блоги

Рекомендаций по книгам