Como verificar se a variável é array? ... ou algo semelhante a array

90

Quero usar um foreachloop com uma variável, mas essa variável pode ser de muitos tipos diferentes, NULLpor exemplo.

Portanto, antes de foreachtestá-lo:

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

Mas percebi que também pode ser uma classe que implementa Iteratorinterface. Talvez eu seja cego, mas como verificar se a classe implementa interface? Existe algo como is_afunção ou inheritsoperador? Eu descobri class_implements, posso usar, mas talvez haja algo mais simples?

E segundo, mais importante, suponho que essa função exista, seria o suficiente para verificar se a variável is_arrayou "implementa Iteratorinterface" ou devo testar algo mais?

Voitcus
fonte
2
if ($ var instanceof ArrayIterator)
Alexey
Sim, tinha tanta certeza de que não ia funcionar que nem olhei para o manual ...
Voitcus

Respostas:

79

Se você estiver usando foreachdentro de uma função e estiver esperando uma matriz ou um objeto Traversable, você pode digitar hint essa função com:

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

Se você não estiver usando foreachdentro de uma função ou se espera as duas, você pode simplesmente usar esta construção para verificar se você pode iterar na variável:

if (is_array($a) or ($a instanceof Traversable))
Sapato
fonte
Obrigado. Espero que seja o suficiente e não haja / haverá nenhuma outra construção de linguagem que possa ser iterada.
Voitcus
Eu descobri is_arrayque era caro. O custo computacional pareceu aumentar com o tamanho do array (o que não faz sentido, pois é apenas verificar se é um array). Mas isso aconteceu comigo de forma chocante em uma biblioteca. Veja meu comentário na pergunta vinculada. Funcionará instanceof Traversablecom matrizes? Não tive a chance de testar seu desempenho.
ADTC
@ADTC AFAIR um array é uma instância de Traversableentão sim.
Sapato
1
@Shoe eu tentei aqui . Com $var = array(1,2,3);os resultados são: is_array($var) = truee $var instanceof Traversable = false.
ADTC de
@ADTC Sim, acabei de verificar. Matrizes não implementam Iteratore, portanto, não funcionam com Traversable.
Sapato
15

foreachpode lidar com matrizes e objetos. Você pode verificar isso com:

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

Você não precisa verificar especificamente, Traversablepois outros sugeriram em suas respostas, porque todos os objetos - como todos os arrays - podem ser percorridos em PHP.

Mais tecnicamente:

foreachtrabalha com todos os tipos de travessíveis, ou seja, com matrizes, com objetos simples (onde as propriedades acessíveis são percorridas) e Traversableobjetos (ou melhor, objetos que definem o get_iteratormanipulador interno ).

( fonte )

Simplesmente dito na programação PHP comum, sempre que uma variável é

  • uma matriz
  • um objeto

e não é

  • NULO
  • um recurso
  • um escalar

você pode usar foreachnele.

hakre
fonte
5

Você pode verificar a instância de Traversablecom uma função simples. Isso funcionaria para tudo isso IteratorporqueIterator extends Traversable

function canLoop($mixed) {
    return is_array($mixed) || $mixed instanceof Traversable ? true : false;
}
Baba
fonte
A parte "? true: false" é redundante. instanceof já fornece um valor bool como resultado.
Linas,
2
<?php
$var = new ArrayIterator();

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

retorna bool(false)oubool(true)

Alexey
fonte
0

Funções

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

Exemplo

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

Desde o PHP 7.1 existe um pseudo-tipo iterableexatamente para este propósito. A sugestão de tipo iterableaceita qualquer array, bem como qualquer implementação da Traversableinterface. PHP 7.1 também introduziu a função is_iterable(). Para versões mais antigas, veja outras respostas aqui para realizar a aplicação de tipo equivalente sem os recursos integrados mais recentes.

Fair play: como BlackHole apontou, esta questão parece ser uma duplicata de objetos Iteráveis ​​e dicas de tipo de array? e sua resposta vai em mais detalhes do que a minha.

desmaio
fonte