Wie überprüfe ich, ob eine Variable ein Array ist?… Oder etwas Array-ähnliches

90

Ich möchte eine foreachSchleife mit einer Variablen verwenden, aber diese Variable kann NULLzum Beispiel viele verschiedene Typen haben .

Also bevor foreachich es teste:

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

Mir wurde jedoch klar, dass es sich auch um eine Klasse handeln kann, die eine IteratorSchnittstelle implementiert . Vielleicht bin ich blind, aber wie kann ich überprüfen, ob die Klasse eine Schnittstelle implementiert? Gibt es so etwas wie is_aFunktion oder inheritsOperator? Ich habe festgestellt class_implements, ich kann es verwenden, aber vielleicht gibt es etwas Einfacheres?

Und zweitens, wichtiger, ich nehme an, diese Funktion existiert, würde ausreichen, um zu überprüfen, ob die Variable is_arrayoder " IteratorSchnittstelle implementiert " oder sollte ich auf etwas mehr testen?

Voitcus
quelle
2
if ($ var Instanz von ArrayIterator)
Alexey
Ja, ich war mir so sicher, dass dies nicht funktionieren würde, wenn ich nicht einmal im Handbuch
nachgesehen hätte
2
Mögliches Duplikat von Iterable-Objekten und Array-Typ-Hinweisen?
Blackhole

Antworten:

78

Wenn Sie foreachinnerhalb einer Funktion verwenden und ein Array oder ein Traversable- Objekt erwarten , können Sie einen Hinweis auf diese Funktion eingeben mit:

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

Wenn Sie keine foreachFunktion verwenden oder beides erwarten , können Sie mit diesem Konstrukt einfach überprüfen, ob Sie die Variable durchlaufen können:

if (is_array($a) or ($a instanceof Traversable))
Schuh
quelle
Vielen Dank. Ich hoffe es ist genug und es gibt / wird keine anderen Sprachkonstrukte geben, die iteriert werden können.
Voitcus
Ich hatte festgestellt is_array, dass es teuer war. Die Rechenkosten schienen mit der Größe des Arrays zu steigen (was keinen Sinn macht, da nur geprüft wird, ob es sich um ein Array handelt). Aber es ist mir schockierend in einer Bibliothek passiert. Siehe meinen Kommentar in der verknüpften Frage. Funktioniert instanceof Traversablemit Arrays? Ich hatte keine Gelegenheit, seine Leistung zu testen.
ADTC
@ADTC AFAIR ein Array ist eine Instanz von Traversableso ja.
Schuh
1
@ Schuh Ich habe es hier versucht . Mit $var = array(1,2,3);den Ergebnissen sind: is_array($var) = trueund $var instanceof Traversable = false.
ADTC
@ADTC Ja, gerade überprüft. Arrays werden nicht implementiert Iteratorund funktionieren daher nicht mit Traversable.
Schuh
15

foreachkann mit Arrays und Objekten umgehen. Sie können dies überprüfen mit:

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

Sie müssen nicht speziell nachsehen, Traversablewie andere es in ihren Antworten angedeutet haben, da alle Objekte - wie alle Arrays - in PHP durchlaufbar sind.

Technischer:

foreachfunktioniert mit allen Arten von Traversables, dh mit Arrays, mit einfachen Objekten (bei denen die zugänglichen Eigenschaften durchlaufen werden) und TraversableObjekten (oder vielmehr Objekten, die den internen get_iteratorHandler definieren ).

( Quelle )

Einfach gesagt in der gängigen PHP-Programmierung, wann immer eine Variable ist

  • eine Anordnung
  • ein Objekt

und ist nicht

  • NULL
  • eine Ressource
  • ein Skalar

Sie können darauf verwenden foreach.

hakre
quelle
5

Sie können die Instanz von Traversablemit einer einfachen Funktion überprüfen . Dies würde für all dies funktionieren, IteratorweilIterator extends Traversable

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}
Baba
quelle
2
<?php
$var = new ArrayIterator();

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

gibt bool(false)oder zurückbool(true)

Alexey
quelle
0

Funktionen

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

Beispiel

<?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
quelle
0

Seit PHP 7.1 gibt es iterablegenau für diesen Zweck einen Pseudotyp . Typhinweise iterableakzeptieren jedes Array sowie jede Implementierung der TraversableSchnittstelle. PHP 7.1 führte auch die Funktion ein is_iterable(). Für ältere Versionen finden Sie hier andere Antworten, um die gleichwertige Typdurchsetzung ohne die neueren integrierten Funktionen zu erreichen.

Fairplay: Wie BlackHole hervorhob, scheint diese Frage ein Duplikat von Iterable-Objekten und Hinweisen auf Array-Typen zu sein. und seine oder ihre Antwort geht detaillierter als meine.

Ohnmachtssignal
quelle