Jak sprawdzić, czy zmienna jest tablicą?… Lub czymś podobnym do tablicy

90

Chcę użyć foreachpętli ze zmienną, ale ta zmienna może mieć NULLna przykład wiele różnych typów .

Więc zanim foreachto przetestuję:

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

Ale zdałem sobie sprawę, że może to być również klasa implementująca Iteratorinterfejs. Może jestem niewidomy, ale jak sprawdzić, czy klasa implementuje interfejs? Czy jest coś takiego jak is_afunkcja lub inheritsoperator? Znalazłem class_implements, mogę to wykorzystać, ale może jest coś prostszego?

Po drugie, co ważniejsze, przypuszczam, że ta funkcja istnieje, wystarczyłoby do sprawdzenia, czy zmienna is_arraylub „ Iteratorinterfejs implementuje ”, czy też powinienem przetestować coś więcej?

Voitcus
źródło
2
if ($ var instanceof ArrayIterator)
Alexey
Tak, byłem pewien, że to nie zadziała, że ​​nawet nie zajrzałem do instrukcji ...
Voitcus

Odpowiedzi:

80

Jeśli używasz foreachwewnątrz funkcji i spodziewasz się tablicy lub obiektu Traversable , możesz wpisać wskazówkę dotyczącą tej funkcji za pomocą:

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

Jeśli nie używasz foreachwewnątrz funkcji lub spodziewasz się obu , możesz po prostu użyć tej konstrukcji, aby sprawdzić, czy możesz iterować po zmiennej:

if (is_array($a) or ($a instanceof Traversable))
But
źródło
Dzięki. Mam nadzieję, że to wystarczy i nie ma / nie będzie innych konstrukcji językowych, które można by iterować.
Voitcus
Okazało się, is_arrayże jest drogi. Koszt obliczeniowy wydawał się wzrastać wraz z rozmiarem tablicy (co nie ma sensu, ponieważ sprawdza tylko, czy jest to tablica). Ale przydarzyło mi się to szokująco w bibliotece. Zobacz mój komentarz w powiązanym pytaniu. Będzie instanceof Traversabledziałać z tablicami? Nie miałem okazji przetestować jego działania.
ADTC
@ADTC AFAIR tablica jest instancją Traversabletak.
But
1
@Shoe Wypróbowałem to tutaj . Z $var = array(1,2,3);wynikami są: is_array($var) = truei $var instanceof Traversable = false.
ADTC,
@ADTC Tak, właśnie sprawdzone. Tablice nie są implementowane Iteratori dlatego nie działają z Traversable.
But
15

foreachmoże obsługiwać tablice i obiekty. Możesz to sprawdzić za pomocą:

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

Nie musisz specjalnie sprawdzać, Traversableponieważ inni zasugerowali to w swoich odpowiedziach, ponieważ wszystkie obiekty - podobnie jak wszystkie tablice - są przejezdne w PHP.

Bardziej technicznie:

foreachdziała z wszystkimi rodzajami obiektów przechodnich, tj. z tablicami, ze zwykłymi obiektami (gdzie przechodzą dostępne właściwości) i Traversableobiektami (a raczej obiektami definiującymi wewnętrzną get_iteratorprocedurę obsługi).

( źródło )

Mówiąc najprościej w typowym programowaniu PHP, gdziekolwiek jest zmienna

  • tablica
  • obiekt

i nie jest

  • ZERO
  • zasób
  • skalar

możesz foreachna nim użyć .

hakre
źródło
5

Możesz sprawdzić instancję Traversableza pomocą prostej funkcji. To by zadziałało na to wszystko z IteratorpowoduIterator extends Traversable

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}
Baba
źródło
„? prawda: fałsz” jest zbędna. instanceof już daje w wyniku wartość bool.
Linas
2
<?php
$var = new ArrayIterator();

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

zwraca bool(false)lubbool(true)

Alexey
źródło
0

Funkcje

<?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;
}

Przykład

<?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)
Eduardo Cuomo
źródło
0

Od PHP 7.1 istnieje pseudo typ iterablesłużący dokładnie do tego celu. Podpowiedzi do typu iterableakceptują dowolną tablicę, a także każdą implementację Traversableinterfejsu. PHP 7.1 również wprowadził tę funkcję is_iterable(). W przypadku starszych wersji zobacz inne odpowiedzi tutaj, aby przeprowadzić równoważne wymuszanie typu bez nowszych wbudowanych funkcji.

Fair play: jak wskazał BlackHole, to pytanie wydaje się być duplikatem obiektów iterowalnych i podpowiedzi typu tablicy? a jego odpowiedź jest bardziej szczegółowa niż moja.

faintsignal
źródło