Argumento no válido suministrado para foreach()


A menudo me sucede manejar datos que pueden ser una matriz o una variable nula y alimentar algunos foreach con estos datos.

$values = get_values();

foreach ($values as $value){
  ...
}

Cuando alimentas un foreach con datos que no son una matriz, obtienes una advertencia:

Advertencia: Argumento no válido suministrado para foreach() en [...]

Asumiendo que no es posible refactorizar la función get_values() para devolver siempre una matriz (compatibilidad con versiones anteriores, no hay código fuente disponible, cualquier otra razón), me pregunto cuál es la forma más limpia y eficiente de evitar estas advertencias:

  • Casting $values to array
  • Inicializando $values a array
  • Envolviendo el foreach con un if
  • Otros (por favor sugiera)
 248
Author: Geoffrey Hale, 2010-04-13

18 answers

Personalmente me parece que esto es el más limpio - no estoy seguro de si es el más eficiente, mente!

if (is_array($values) || is_object($values))
{
    foreach ($values as $value)
    {
        ...
    }
}

La razón de mi preferencia es que no asigna una matriz vacía cuando no tienes nada para empezar de todos modos.

 424
Author: Andy Shellam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-27 20:57:40

¿Qué tal este? mucho más limpio y todo en una sola línea.

foreach ((array) $items as $item) {
 // ...
 }
 76
Author: Ajith R Nair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-08 17:08:27

Normalmente uso una construcción similar a esta:

/**
 * Determine if a variable is iterable. i.e. can be used to loop over.
 *
 * @return bool
 */
function is_iterable($var)
{
    return $var !== null 
        && (is_array($var) 
            || $var instanceof Traversable 
            || $var instanceof Iterator 
            || $var instanceof IteratorAggregate
            );
}

$values = get_values();

if (is_iterable($values))
{
    foreach ($values as $value)
    {
        // do stuff...
    }
}

Tenga en cuenta que esta versión en particular no se prueba, se escribe directamente en SO desde la memoria.

Edit: added Traversable check

 37
Author: Kris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-25 13:47:49

Por favor, no dependa de la fundición como solución , a pesar de que otros están sugiriendo esto como una opción válida para evitar un error, podría causar otro.

Tenga en cuenta: Si espera que se devuelva una forma específica de matriz, esto podría fallarle. Se requieren más controles para eso.

Por ejemplo, lanzar un booleano a un array (array)bool, NO dará como resultado un array vacío, sino un array con un elemento que contiene el valor booleano como un int: [0=>0] o [0=>1].

Escribí una prueba rápida para presentar este problema. (Aquí hay una prueba de copia de seguridad en caso de que la primera url de prueba falle.)

Se incluyen pruebas para: null, false, true, a class, an array y undefined.


Siempre pruebe su entrada antes de usarla en foreach. Sugerencias:

  1. Comprobación rápida de tipos : $array = is_array($var) or is_object($var) ? $var : [] ;
  2. Escriba matrices de sugerencia en métodos antes de usar un foreach y especificando tipos de retorno
  3. Envolviendo foreach dentro de if
  4. Usando try{}catch(){} bloques
  5. Diseño de código / pruebas adecuadas antes de las versiones de producción
  6. Para probar un array contra la forma adecuada se puede usar array_key_exists en una clave específica, o probar la profundidad de un array (cuando es uno !).
  7. Siempre extraiga sus métodos de ayuda en el espacio de nombres global de una manera de reducir el código duplicado
 13
Author: AARTT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:54

Prueba esto:

//Force array
$dataArr = is_array($dataArr) ? $dataArr : array($dataArr);
foreach ($dataArr as $val) {
  echo $val;
}

;)

 6
Author: GigolNet Guigolachvili,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-30 12:52:18
$values = get_values();

foreach ((array) $values as $value){
  ...
}

El problema es siempre nulo y la colada es, de hecho, la solución de limpieza.

 4
Author: boctulus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-02 16:59:44

En primer lugar, cada variable debe ser inicializada. Siempre.
El casting no es una opción.
si get_values (); puede devolver diferentes variables de tipo, este valor debe ser comprobado, por supuesto.

 3
Author: Your Common Sense,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-13 14:11:25

Extensión más concisa del código de @Kris

function secure_iterable($var)
{
    return is_iterable($var) ? $var : array();
}

foreach (secure_iterable($values) as $value)
{
     //do stuff...
}

Especialmente para usar dentro del código de plantilla

<?php foreach (secure_iterable($values) as $value): ?>
    ...
<?php endforeach; ?>
 3
Author: HongKilDong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:33:24
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

Esto no comprueba si es un array, pero salta el bucle si la variable es null o un array vacío.

 2
Author: T30,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-14 02:41:50

Si está utilizando php7 y desea manejar solo errores indefinidos, esta es la IMHO

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}
 2
Author: Edwin Rodríguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-09 15:27:03

No estoy seguro de si este es el caso, pero este problema parece ocurrir varias veces al migrar sitios de Wordpress o migrar sitios dinámicos en general. Si este es el caso, asegúrese de que el alojamiento al que está migrando use la misma versión de PHP que usa su sitio anterior.

Si no está migrando su sitio y esto es solo un problema que ha surgido, intente actualizar a PHP 5. Esto soluciona algunos de estos problemas. Puede parecer una solución tonta, pero hizo el truco para mí.

 1
Author: Erik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-12 13:16:28

Caso excepcional para este aviso se produce si se establece la matriz a null dentro del bucle foreach

if (is_array($values))
{
    foreach ($values as $value)
    {
        $values = null;//WARNING!!!
    }
}
 1
Author: Farid Movsumov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-18 09:24:52

Qué tal esta solución:

$type = gettype($your_iteratable);
$types = array(
    'array',
    'object'
);

if (in_array($type, $types)) {
    // foreach code comes here
}
 1
Author: Julian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-01 12:04:11

También parece haber una relación con el medio ambiente:

Tuve el error "invalid argument supplied foreach()" solo en el entorno dev, pero no en prod (estoy trabajando en el servidor, no en localhost).

A pesar del error, un var_dump indicó que la matriz estaba bien allí (en ambos casos app y dev).

El if (is_array($array)) alrededor del foreach ($array as $subarray) resolvió el problema.

Lo siento, no puedo explicar la causa, pero como me llevó un tiempo encontrar una solución, pensé en es mejor compartir esto como una observación.

 0
Author: araldh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-22 11:36:42

Usaré una combinación de empty, isset e is_array como

$array = ['dog', 'cat',  'lion'];

if(!empty($array)  && isset($array)  && is_array($array){
//loop
foreach ($array as $values) {
echo $values; 
}
}
 0
Author: Akintunde-Rotimi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-06 17:10:50

Utilice la función is_array, cuando pasará el array al bucle foreach.

if (is_array($your_variable)) {
  foreach ($your_variable as $item) {
   //your code
}
}
 0
Author: Super Model,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-21 21:46:43

Warning argumento no válido suministrado para mostrar tweets de foreach (). vaya a "/wp-content/plugins / display-tweets-php". Luego inserte este código en la línea número 591, funcionará perfectamente.

if (is_array($tweets)){  
        foreach ( $tweets as $tweet ) 
    {
        ...
    }
}
 0
Author: Saad Khanani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-03 02:59:48

Haría lo mismo que Andy pero usaría la función 'empty'.

Así:

if(empty($yourArray))
{echo"<p>There's nothing in the array.....</p>";}
else
{
foreach ($yourArray as $current_array_item)
  {
    //do something with the current array item here
  } 
}
 -3
Author: as_bold_as_love,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-30 17:40:04