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

Что такое ISA Server. ISA Server простыми словами. Настройка ISA

Web

Как обрезать ссылку Гугл, какой существует сервис для сжатия ссылок

Web

PHP валидация/регулярное выражение для URL

Касперский SSL-сертификат для сайта: почему важно его получить?
Web

Касперский SSL-сертификат для сайта: почему важно его получить?

×