Как проверить, является ли переменная массивом?… Или чем-то вроде массива

90

Я хочу использовать foreachцикл с переменной, но, например, эта переменная может быть разных типов NULL.

Итак, прежде чем foreachя его протестирую:

if(is_array($var)){
  foreach($var as ...

Но я понял, что это также может быть класс, реализующий Iteratorинтерфейс. Может, я слепой, но как проверить, реализует ли класс интерфейс? Есть что-то вроде is_aфункции или inheritsоператора? Нашел class_implements, могу пользоваться, а может есть что попроще?

И во-вторых, что более важно, я полагаю, что эта функция существует, было бы достаточно, чтобы проверить, является ли переменная is_arrayили «реализует Iteratorинтерфейс», или я должен проверить что-то еще?

Войткус
источник
2
if ($ var instanceof ArrayIterator)
Алексей
Да, я был так уверен , что это не будет работать , что даже не заглядывал к руководству ...
Voitcus

Ответы:

80

Если вы используете foreachвнутри функции и ожидаете массив или объект Traversable, вы можете ввести подсказку для этой функции с помощью:

function myFunction(array $a)
function myFunction(Traversable)

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

if (is_array($a) or ($a instanceof Traversable))
Обувь
источник
Спасибо. Я надеюсь, что этого достаточно, и не будет / не будет никаких других языковых конструкций, которые можно было бы повторять.
Voitcus
Я обнаружил, is_arrayчто это дорого. Вычислительные затраты, казалось, увеличивались с увеличением размера массива (что не имеет смысла, поскольку он просто проверяет, является ли он массивом). Но со мной случилось ужасное в библиотеке. См. Мой комментарий в связанном вопросе. Будет instanceof Traversableработать с массивами? У меня не было возможности проверить его работоспособность.
ADTC
@ADTC AFAIR массив является экземпляром, Traversableтак что да.
Shoe
1
@ Обувь Я пробовала здесь . С $var = array(1,2,3);результатами: is_array($var) = trueи $var instanceof Traversable = false.
ADTC
@ADTC Да, только что проверил. Массивы не реализуются Iteratorи поэтому не работают с Traversable.
Shoe
15

foreachможет обрабатывать массивы и объекты. Вы можете проверить это с помощью:

$can_foreach = is_array($var) || is_object($var);
if ($can_foreach) {
    foreach ($var as ...
}

Вам не нужно специально проверять это, Traversableпоскольку другие намекали на это в своих ответах, потому что все объекты - как и все массивы - можно перемещать в PHP.

Более технически:

foreachработает со всеми видами перемещаемых объектов, то есть с массивами, с простыми объектами (где просматриваются доступные свойства) и Traversableобъектами (или, скорее, объектами, которые определяют внутренний get_iteratorобработчик).

( источник )

Проще говоря в обычном программировании PHP, когда переменная

  • массив
  • объект

и не

  • ЗНАЧЕНИЕ NULL
  • ресурс
  • скаляр

вы можете использовать foreachна нем.

hakre
источник
5

Вы можете проверить экземпляр Traversableс помощью простой функции. Это сработает для всего этого, Iteratorпотому чтоIterator extends Traversable

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}
Баба
источник
Часть «? true: false» является избыточной. instanceof в результате уже дает значение типа bool.
Линас,
2
<?php
$var = new ArrayIterator();

var_dump(is_array($var), ($var instanceof ArrayIterator));

возвращается bool(false)илиbool(true)

Алексей
источник
0

Функции

<?php

/**
 * Is Array?
 * @param mixed $x
 * @return bool
 */
function isArray($x) : bool {
  return !isAssociative($x);
}

/**
 * Is Associative Array?
 * @param mixed $x
 * @return bool
 */
function isAssociative($x) : bool {
  if (!is_array($array)) {
    return false;
  }
  $i = count($array);
  while ($i > 0) {
    if (!isset($array[--$i])) {
      return true;
    }
  }
  return false;
}

пример

<?php

$arr = [ 'foo', 'bar' ];
$obj = [ 'foo' => 'bar' ];

var_dump(isAssociative($arr));
# bool(false)

var_dump(isAssociative($obj));
# bool(true)

var_dump(isArray($obj));
# bool(false)

var_dump(isArray($arr));
# bool(true)
Эдуардо Куомо
источник
0

Начиная с PHP 7.1 существует псевдотип iterableименно для этой цели. Подсказка типа iterableпринимает любой массив, а также любую реализацию Traversableинтерфейса. PHP 7.1 также представил эту функцию is_iterable(). Для более старых версий см. Другие ответы здесь, чтобы выполнить принудительное применение эквивалентного типа без новых встроенных функций.

Честная игра: как указал BlackHole, этот вопрос, похоже, является дубликатом Iterable объектов и подсказок типа массива? и его или ее ответ более подробен, чем мой.

слабый сигнал
источник