¿Cómo comprobar si la variable es una matriz? ... o algo similar a una matriz

90

Quiero usar un foreachbucle con una variable, pero esta variable puede ser de muchos tipos diferentes, NULLpor ejemplo.

Entonces, antes de foreachprobarlo:

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

Pero me di cuenta de que también puede ser una clase que implemente Iteratorinterfaz. Tal vez soy ciego, pero ¿cómo verificar si la clase implementa la interfaz? ¿Existe algo como is_afunción u inheritsoperador? Lo encontré class_implements, puedo usarlo, pero ¿tal vez hay algo más simple?

Y segundo, más importante, supongo que existe esta función, ¿sería suficiente para comprobar si la variable is_arrayo "implementa la Iteratorinterfaz" o debería probar algo más?

Voitcus
fuente
2
if ($ var instancia de ArrayIterator)
Alexey
Sí, estaba tan seguro de que esto no funcionaría que ni siquiera había mirado el manual ...
Voitcus
2
¿Posible duplicado de objetos Iterables y sugerencias de tipo de matriz?
Blackhole

Respuestas:

79

Si está utilizando foreachdentro de una función y espera una matriz o un objeto Traversable , puede escribir una pista de esa función con:

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

Si no está usando foreachdentro de una función o está esperando ambas , simplemente puede usar esta construcción para verificar si puede iterar sobre la variable:

if (is_array($a) or ($a instanceof Traversable))
Zapato
fuente
Gracias. Espero que sea suficiente y que no haya / no habrá otras construcciones de lenguaje que puedan iterarse.
Voitcus
Me pareció is_arraycaro. El costo computacional pareció aumentar con el tamaño de la matriz (lo cual no tiene sentido ya que solo se trata de verificar si es una matriz). Pero me pasó espantosamente en una biblioteca. Vea mi comentario en la pregunta vinculada. ¿ instanceof TraversableFuncionará con matrices? No tuve la oportunidad de probar su rendimiento.
ADTC
@ADTC AFAIR una matriz es una instancia de Traversableentonces sí.
Zapato
1
@Zapato Lo probé aquí . Con $var = array(1,2,3);los resultados son: is_array($var) = truey $var instanceof Traversable = false.
ADTC
@ADTC Sí, recién comprobado. Las matrices no se implementan Iteratory, por lo tanto, no funcionan con Traversable.
Zapato
15

foreachpuede manejar matrices y objetos. Puedes comprobar esto con:

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

No necesita verificar específicamente, Traversableya que otros lo han insinuado en sus respuestas, porque todos los objetos, como todas las matrices, se pueden atravesar en PHP.

Más técnicamente:

foreachtrabaja con todo tipo de transitables, es decir, con matrices, con objetos planos (donde se atraviesan las propiedades accesibles) y Traversableobjetos (o más bien objetos que definen el get_iteratormanejador interno ).

( fuente )

Dicho simplemente en la programación PHP común, siempre que una variable es

  • una matriz
  • un objeto

y no es

  • NULO
  • un recurso
  • un escalar

puedes usarlo foreach.

hakre
fuente
5

Puede verificar la instancia de Traversablecon una función simple. Esto funcionaría para todo esto IteratorporqueIterator extends Traversable

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}
Baba
fuente
La parte "? verdadero: falso" es redundante. instanceof ya da un valor bool como resultado.
Linas
2
<?php
$var = new ArrayIterator();

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

devuelve bool(false)obool(true)

Alexey
fuente
0

Funciones

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

Ejemplo

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

Desde PHP 7.1 existe un pseudo-tipo iterableexactamente para este propósito. La sugerencia de tipo iterableacepta cualquier matriz, así como cualquier implementación de la Traversableinterfaz. PHP 7.1 también introdujo la función is_iterable(). Para versiones anteriores, consulte otras respuestas aquí para lograr la aplicación de tipo equivalente sin las funciones integradas más nuevas.

Juego limpio: como señaló BlackHole, esta pregunta parece ser un duplicado de objetos Iterables y sugerencias de tipo de matriz. y su respuesta es más detallada que la mía.

desmayo
fuente