Avatar ·

Как проверить, является ли массив в PHP ассоциативным или последовательным (индексированным)?

Всем привет! Я только начал изучать PHP и столкнулся с непонятной ситуацией. Я знаю, что в PHP есть два типа массивов: обычные (последовательные) с числовыми ключами от 0 и ассоциативные, где ключи — строки. Но на деле всё перемешано: массив может начинаться с ключа 0, потом идти строка, а потом снова число. Или ключи могут быть числами, но не по порядку (например, 0, 5, 10). Мне нужно написать функцию, которая обрабатывает данные из формы. Если массив последовательный (то есть ключи идут по порядку: 0, 1, 2, 3...), я применяю одну логику. Если ассоциативный (например, ключи 'name', 'email', 'age') — другую. Но стандартная проверка через `array_keys()` не даёт однозначного ответа, потому что массив типа `[0 => 'a', 2 => 'b']` формально числовой, но не последовательный. Вот пример, который меня смущает: ```php $arr1 = ['a', 'b', 'c']; // последовательный $arr2 = ['name' => 'John', 'age' => 30]; // ассоциативный $arr3 = [0 => 'x', 1 => 'y', 3 => 'z']; // числовой, но с пропуском $arr4 = ['a', 'b', 'c' => 'd']; // смешанный ``` Как правильно и надёжно определить, является ли массив именно последовательным (индексированным от 0 без пропусков) или ассоциативным? Есть ли встроенная функция в PHP для этого? Буду благодарен за примеры кода. <<>>

Основной способ: проверка ключей на последовательность

В PHP нет единой встроенной функции для проверки типа массива, но задачу можно решить несколькими способами. Самый надёжный — проверить, что все ключи являются целыми числами и образуют строгую последовательность от 0 до count($array)-1.

Вот простая и эффективная функция:

function isSequentialArray(array $array): bool {
    if (empty($array)) {
        return true; // Пустой массив считаем последовательным
    }
    return array_keys($array) === range(0, count($array) - 1);
}

Разберём, как это работает:

  • array_keys($array) — возвращает все ключи массива.
  • range(0, count($array) - 1) — генерирует эталонный массив [0, 1, 2, ..., N-1].
  • Оператор === сравнивает не только значения, но и типы (строгое сравнение).

Примеры использования:

$arr1 = ['a', 'b', 'c'];
var_dump(isSequentialArray($arr1)); // true

$arr2 = ['name' => 'John', 'age' => 30];
var_dump(isSequentialArray($arr2)); // false

$arr3 = [0 => 'x', 1 => 'y', 3 => 'z'];
var_dump(isSequentialArray($arr3)); // false (пропущен ключ 2)

$arr4 = ['a', 'b', 'c' => 'd'];
var_dump(isSequentialArray($arr4)); // false (есть строковый ключ)

$arr5 = [5 => 'start', 6 => 'end'];
var_dump(isSequentialArray($arr5)); // false (начинается не с 0)

$empty = [];
var_dump(isSequentialArray($empty)); // true (пустой массив)

Более производительный вариант для больших массивов

Если массив содержит миллионы элементов, создание двух массивов через array_keys() и range() может быть затратным. Вот альтернатива без копирования ключей:

function isSequentialArray(array $array): bool {
    $expectedKey = 0;
    foreach ($array as $key => $value) {
        if ($key !== $expectedKey) {
            return false;
        }
        $expectedKey++;
    }
    return true;
}

Этот вариант проходит по массиву один раз и проверяет каждый ключ на лету. Он быстрее и использует меньше памяти.

Дополнительные нюансы

Обратите внимание: в PHP массивы могут содержать элементы с ключом null или пустой строкой. Функции выше корректно обработают такие случаи:

  • Ключ null будет преобразован в пустую строку — это не целое число, поэтому массив будет считаться ассоциативным.
  • Если массив начинается с ключа 0, но потом идёт ключ 'a' — функция вернёт false.

Если вам нужно просто узнать, есть ли в массиве строковые ключи (ассоциативность в широком смысле), можно использовать такой подход:

function isAssociative(array $array): bool {
    if (empty($array)) {
        return false;
    }
    foreach ($array as $key => $value) {
        if (!is_int($key)) {
            return true;
        }
    }
    return false;
}

Но помните: числовой массив с пропусками (как [0 => 'a', 2 => 'b']) не будет считаться ассоциативным в этой функции, хотя и не является последовательным. Выбирайте подход в зависимости от вашей задачи.

<<>>

Использование array_values() для сброса ключей

Ещё один простой способ — сравнить исходный массив с его "переиндексированной" версией. Если после применения array_values() массив не изменился, значит, он был последовательным.

function isSequentialArray(array $array): bool {
    return $array === array_values($array);
}

Как это работает: array_values() возвращает массив с числовыми ключами от 0, сбрасывая любые существующие ключи. Затем строгое сравнение === проверяет, совпадают ли исходный и новый массивы. Если ключи уже были последовательными — массивы будут идентичны.

Пример:

$arr1 = ['a', 'b', 'c']; // true
$arr2 = ['name' => 'John']; // false (ключи изменятся)
$arr3 = [0 => 'x', 1 => 'y', 3 => 'z']; // false (пропуск)
$arr4 = [5 => 'start']; // false (начинается с 5)

Когда это может быть полезно

Этот метод хорош, когда вам нужно просто проверить, можно ли безопасно обращаться к элементам по числовому индексу без риска получить unexpected. Например, перед передачей массива в функцию, ожидающую список (list).

Недостаток: для больших массивов array_values() создаёт копию, что увеличивает потребление памяти. Для критичных по производительности мест лучше использовать итеративный подход из первого ответа.