Web

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

PHP рассматривает все массивы как ассоциативные, поэтому встроенных функций для этого нет. Может ли кто-нибудь порекомендовать довольно эффективный способ проверить, содержит ли массив только числовые ключи?

По сути, я хочу различать это:

$sequentialArray = [

    'apple', 'orange', 'tomato', 'carrot'

];

 

и это:

$assocArray = [

    'fruit1' => 'apple',

    'fruit2' => 'orange',

    'veg1' => 'tomato',

    'veg2' => 'carrot'

];

 

Ответ 1

Вы задали два вопроса, которые не совсем эквивалентны:

  • Во-первых, как определить, имеет ли массив только числовые ключи?

  • Во-вторых, как определить, есть ли в массиве последовательные числовые ключи, начиная с 0?

Подумайте, какое из этих поведений вам действительно нужно озможно, для ваших целей подойдет любой из них).

Для второго вопроса (проверка того, является ли массив с нулевым индексом и последовательным) вы можете использовать следующую функцию:

function isAssoc(array $arr) {

    if (array() === $arr) return false;

    return array_keys($arr) !== range(0, count($arr) - 1);

}

var_dump(isAssoc(['a', 'b', 'c'])); // false

var_dump(isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); // false

var_dump(isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); // true

var_dump(isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); // true

 

Ответ 2

Многие ответившие на этот вопрос не понимают, как массивы работают в PHP. Из документации по массиву:

Ключ может быть целым числом или строкой. Если ключ является стандартным представлением целого числа, он будет интерпретироваться как таковой (т. е. «8» будет интерпретироваться как 8, а «08» будет интерпретироваться как «08»). Значения в ключе усекаются до целого числа. Индексированные и ассоциативные типы массивов это один и тот же тип в PHP, который может содержать как целочисленные, так и строковые индексы.

 Другими словами, не существует такой вещи, как ключ массива «8», потому что он всегда будет (незаметно) преобразован в целое число 8. Таким образом, попытки различать целые числа и числовые строки не нужны.

Если вам нужен наиболее эффективный способ проверки массива на наличие нецелочисленных ключей без создания копии части массива (например, array_keys()) или всего массива (например, foreach):

function keyedNext( &$arr, &$k){

    $k = key($arr);

    return next($arr);

}

 

for ($k = key(reset($my_array)); is_int($k); keyedNext($my_array,$k))

    $onlyIntKeys = is_null($k);

 

Это работает, потому что key() возвращает NULL, когда текущая позиция массива недействительна, а NULL никогда не может быть допустимым ключом (если вы попытаетесь использовать NULL в качестве ключа массива, он будет незаметно преобразован в "").

 

Ответ 3

Как указано в ОП:

PHP рассматривает все массивы как ассоциативные.

 Не совсем разумно писать функцию, проверяющую ассоциативность массива.  Итак, прежде всего: что такое ключ в массиве PHP?

Ключ может быть либо целым числом, либо строкой.

 Это означает, что есть 3 возможных случая:

  • Случай 1. Все ключи числовые/целые.

  • Случай 2. Все ключи строки.

  • Случай 3. Некоторые ключи являются строками, некоторые числовыми/целыми числами.

Мы можем проверить каждый случай с помощью следующих функций.

Случай 1: все ключичисловые/целые.

ПримечаниеЭта функция также возвращает значение true для пустых массивов.

//! Проверьте, является ли входной массив массивом, все ключи которого являются целыми числами.

/*!

    \param[in] $InputArray (array) Входной массив.

    \return (bool) \b true, если входной массив является массивом, ключи которого все целые числа.

*/

function IsArrayAllKeyInt($InputArray) {

    if(!is_array($InputArray)) {

        return false;

    }

    if(count($InputArray) <= 0) {

        return true;

    }

    return array_unique(array_map("is_int", array_keys($InputArray))) === array(true);

}

 Случай 2: все ключи  строки.

ПримечаниеЭта функция также возвращает значение true для пустых массивов.

//! Проверьте, является ли входной массив массивом, все ключи которого являются строками.

/*!

    \param[in] $InputArray (array) Входной массив.

    \return (bool) \b true, если входной массив является массивом, все ключи которого являются строками.

*/

function IsArrayAllKeyString($InputArray) {

    if(!is_array($InputArray)) {

        return false;

    }

    if(count($InputArray) <= 0) {

        return true;

    }

    return array_unique(array_map("is_string", array_keys($InputArray))) === array(true);

}

Случай 3: некоторые ключи являются строками, другие  числовыми/целыми числами.

ПримечаниеЭта функция также возвращает значение true для пустых массивов.

//! Проверьте, является ли входной массив массивом, в котором хотя бы один ключ является целым числом и хотя бы один ключ является строкой.

/*!

    \param[in] $InputArray (array) Входной массив.

    \return (bool) \b true, если входной массив является массивом, в котором хотя бы один ключ является целым числом и хотя бы один ключ является строкой.

*/

function IsArraySomeKeyIntAndSomeKeyString($InputArray){

    if(!is_array($InputArray)) {

        return false;

    }

    if(count($InputArray) <= 0) {

        return true;

    }

    return count(array_unique(array_map("is_string", array_keys($InputArray)))) >= 2;

}

Из этого следует, что:

  • Если значение не является массивомвсе 3 функции возвращают false .

  • Если значение является пустым массивомвсе 3 функции возвращают true
    (что согласно определению, например, «пустой набор является подмножеством любого набора A, потому что все его элементы принадлежат A»).

  • Если значение непустой массивровно 1 функция вернет true.

 

Теперь, чтобы массив был «настоящим» массивом, к которому мы все привыкли, должно быть так:

  • Все его ключи являются числовыми/целыми числами.

  • Его ключи являются последовательными (т. е. увеличиваются на шаг 1).

  • Его ключи начинаются с нуля.

 

Это мы можем проверить с помощью следующей функции.

Случай 3а: ключи являются числовыми/целыми числамипоследовательными и отсчитываются от нуля .

ПримечаниеЭта функция также возвращает значение true для пустых массивов.

//! Проверьте, является ли входной массив массивом, ключи которого являются числовыми, последовательными и нулевыми.

/*!

    \param[in] $InputArray (array) Входной массив.

    \return (bool) \b true, если входной массив является массивом, ключи которого являются числовыми, последовательными и нулевыми.

*/

function IsArrayKeyNumericSequentialZeroBased($InputArray) {

    if(!is_array($InputArray)) {

        return false;

    }

    if(count($InputArray) <= 0) {

        return true;

    }

    return array_keys($InputArray) === range(0, count($InputArray) - 1);

}

Предостережения/подводные камни (или даже более специфические факты о ключах массивов в PHP).

Целочисленные ключи.

Ключи для этих массивов  целые числа:

array(0 => "b");

array(13 => "b");

array(-13 => "b");             // Отрицательные целые числа также являются целыми числами.

array(0x1A => "b");         // Шестнадцатеричная нотация.

Строковые ключи

Ключи для этих массивов строки:

array("fish and chips" => "b");

array("" => "b");                                                              // Пустая строка также является строкой.

array("stackoverflow_email@example.com" => "b");    // Строки могут содержать не алфавитно-цифровые символы.

array("stack\t\"over\"\r\nflow's cool" => "b");                  // Строки могут содержать специальные символы.

array('$tα€k↔øvrflöw' => "b");                                // Строки могут содержать всевозможные символы.

array("말轉ДŁ" => "b");                                         // Как насчет японского/корейского/китайского/русского/польского?

array("fi\x0sh" => "b");                                                 // Строки могут содержать нулевые символы.

array(file_get_contents("https://www.google.com/images/nav_logo114.png") => "b");   // Строки могут быть даже двоичными!

Целочисленные ключи, похожие на строки

Если вы думаете, что ключ array("13" => "b")это строкавы ошибаетесь. Из документации:

Строки, содержащие допустимые целые числа, будут преобразованы в целочисленный тип. Например, ключ «8» будет фактически сохранен под номером 8. С другой стороны, «08» не будет приведено, так как это недопустимое десятичное целое число.

 

Например, ключом к этим массивам являются целые числа:

array("13" => "b");

array("-13" => "b");                        // Негатив, ок.

 

А ключом к этим массивам являются строки:

array("13.     => "b");

array("+13"  => "b");                      // позитивное, ошибка.

array("-013" => "b");

array("0x1A" => "b");                   // Не преобразуются в целые числа, хотя это правильное шестнадцатеричное число.

array("013" => "b");                      // Не преобразуется в целые числа, хотя это действительное восьмеричное число.

array("18446744073709551616" => "b");       // Не преобразуется в целые числа, так как не может поместиться в 64-битное целое число.

Более того, согласно этому документу:

Размер целого числа зависит от платформы, хотя максимальное значение около двух миллиардов является обычным значением (это 32 бита со знаком). 64-битные платформы обычно имеют максимальное значение около 9E18, за исключением Windows, которая всегда 32-битная. PHP не поддерживает целые числа без знака.

 Таким образом, ключ для этого массива может быть целым числом, а может и не быть — это зависит от вашей платформы.

array("60000000000" => "b");                // Ключ массива может быть целым числом или строкой, он может помещаться в 64-битное (но не 32-битное) целое число.

 

Хуже того, PHP имеет тенденцию к ошибкам, если целое число находится рядом с границей 2 31 = 2 147 483 648. Например, в моей локальной среде (PHP 5.3.8 на XAMPP 1.7.7 в Windows 7) 

var_dump(array("2147483647" => "b")) 

выдает

array(1) {

    [2147483647] => string(1) "b"

}   

но для PHP 5.2.5 то же выражение выдает:

array(1) {

    ["2147483647"]=> string(1) "b"

}

Таким образом, в одной среде ключ является целым числом, а в другой  строкой, даже если он 2147483647 и является действительным 32-разрядным целым числом со знаком.

Схожие статьи

Web

Пример использования bind_result/get_result

Современный веб-дизайн. Самые яркие примеры стильных сайтов
Web

Современный веб-дизайн. Самые яркие примеры стильных сайтов

Web

Как получать полезные сообщения об ошибках в PHP?

Селениум: тестирование веб-приложений и другие полезные функции
Web

Селениум: тестирование веб-приложений и другие полезные функции

×