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

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

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

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

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

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

Ответ 1

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

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

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

if (is_array($a) or ($a instanceof Traversable))

Ответ 2

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

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

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

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

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

(источник)

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

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

и не

  • НОЛЬ
  • ресурс
  • скаляр

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

Ответ 3

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

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}

Ответ 4

<?php
$var = new ArrayIterator();

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

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

Ответ 5

функции

<?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)

Ответ 6

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

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