web-dev-qa-db-fra.com

Argument non valide pour la fonction foreach()

Il m'est souvent arrivé de gérer des données qui peuvent être soit un tableau, soit une variable null, et d'alimenter foreach avec ces données.

$values = get_values();

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

Lorsque vous alimentez une foreach avec des données qui ne sont pas un tableau, vous recevez un avertissement:

Avertissement: Argument non valide fourni pour foreach () dans [...]

En supposant qu'il ne soit pas possible de refactoriser la fonction get_values() pour toujours renvoyer un tableau (compatibilité ascendante, code source non disponible, quelle que soit la raison), je me demande quel est le moyen le plus propre et le plus efficace d'éviter ces avertissements:

  • Couler $values dans un tableau
  • Initialisation de $values dans un tableau
  • Enveloppant la foreach avec une if
  • Autre (suggérer s'il vous plaît)
252
Roberto Aloi

Personnellement, je trouve que c’est le plus propre, mais je ne sais pas si c’est le plus efficace.

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

La raison de ma préférence est qu'il n'alloue pas un tableau vide quand vous n'avez rien pour commencer de toute façon.

442
Andy Shellam

Celui-ci, ça va? beaucoup plus propre et tout en une seule ligne.

foreach ((array) $items as $item) {
 // ...
 }
83
Ajith R Nair

J'utilise habituellement une construction semblable à celle-ci:

/**
 * 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...
    }
}

Notez que cette version particulière n’est pas testée, elle est directement saisie dans SO depuis la mémoire.

Edit: ajouté Traversable check

39
Kris

Merci de ne pas utiliser le casting comme solution, Même si d’autres le suggèrent comme une option valide pour éviter une erreur, cela peut en provoquer une autre.

Soyez conscient: Si vous attendez une forme spécifique de tableau à renvoyer, cela peut échouer. Plus de contrôles sont nécessaires pour cela.

Par exemple. En convertissant un booléen dans un tableau (array)bool, NON donnera un tableau vide, mais un tableau avec un élément contenant la valeur booléenne sous la forme int: [0=>0] ou [0=>1].

J'ai écrit un test rapide pour présenter ce problème . (Voici un backup Test au cas où la première URL de test échoue.)

Sont inclus des tests pour: null, false, true, une class, une array et undefined.


Testez toujours votre saisie avant de l’utiliser inforeach. Suggestions: 

  1. Vérification de type rapide : $array = is_array($var) or is_object($var) ? $var : [] ;
  2. Méthodes d'indices de type in avant d'utiliser un foreach et spécifiant les types de retour
  3. Enveloppant pour chaque dedans si
  4. Utilisation de blocs try{}catch(){}
  5. Conception du code/des tests appropriés avant les versions de production
  6. Pour tester un tableau par rapport à sa forme appropriée, vous pouvez utiliser array_key_exists sur une clé spécifique, ou tester la profondeur d'un tableau (s'il en existe une!) .
  7. Toujours extraire vos méthodes d'assistance dans l'espace de noms global de manière à réduire le code en double
13
AARTT

Essaye ça:

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

;)

6
$values = get_values();

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

Le problème est toujours nul et Casting est en fait la solution de nettoyage.

4
boctulus

Tout d'abord, chaque variable doit être initialisée. Toujours.
Casting n'est pas une option.
if get_values ​​(); peut retourner différents types de variables, cette valeur doit être vérifiée, bien sûr.

3
Your Common Sense

Extension plus concise de @ code de Kris

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

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

spécialement pour l'utilisation de code de gabarit intérieur 

<?php foreach (secure_iterable($values) as $value): ?>
    ...
<?php endforeach; ?>
3
HongKilDong

Si vous utilisez php7 et que vous voulez gérer uniquement les erreurs non définies, c'est le plus propre IMHO

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}
2
Edwin Rodríguez
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

Cela ne vérifie pas s'il s'agit d'un tableau, mais ignore la boucle si la variable est null ou un tableau vide.

2
T30

Que diriez-vous de cette solution:

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

if (in_array($type, $types)) {
    // foreach code comes here
}
1
Julian

Je ne sais pas si c'est le cas, mais ce problème semble se produire plusieurs fois lors de la migration de sites WordPress ou de sites dynamiques en général. Si tel est le cas, assurez-vous que l'hébergement vers lequel vous migrez utilise la même version PHP utilisée par votre ancien site.

Si vous ne migrez pas votre site et qu’il s’agit simplement d’un problème qui a été soulevé, essayez de le mettre à jour vers PHP 5. Ce problème est résolu. Cela peut sembler une solution idiote, mais a fait le tour pour moi. 

1
Erik

Un cas exceptionnel pour cet avis se produit si vous définissez un tableau sur null dans une boucle foreach 

if (is_array($values))
{
    foreach ($values as $value)
    {
        $values = null;//WARNING!!!
    }
}
1
Farid Movsumov

Qu'en est-il de définir un tableau vide comme solution de secours si get_value() est vide?
Je ne peux pas penser au chemin le plus court.

$values = get_values() ?: [];

foreach ($values as $value){
  ...
}
0
Quentin Veron

Je vais utiliser une combinaison de empty, isset et is_array

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

if(!empty($array)  && isset($array)  && is_array($array){
//loop
foreach ($array as $values) {
echo $values; 
}
}
0
Akintunde-Rotimi

Il semble aussi y avoir une relation avec l'environnement:

J'ai eu cette erreur "argument invalide fourni foreach ()" seulement dans l'environnement dev, mais pas dans prod (je travaille sur le serveur, pas localhost).

En dépit de l'erreur, var_dump a indiqué que le tableau était bien là (dans les deux cas, app et dev).

Le if (is_array($array)) autour du foreach ($array as $subarray) a résolu le problème.

Désolé, je ne peux pas expliquer la cause, mais comme cela m'a pris un certain temps pour trouver une solution, j'ai pensé à mieux partager cela en tant qu'observation.

0
araldh

Utilisez la fonction is_array, lorsque vous passerez un tableau dans une boucle.

if (is_array($your_variable)) {
  foreach ($your_variable as $item) {
   //your code
}
}
0
Super Model

Avertissement argument non valide fourni pour foreach () display tweets . Allez à "/ wp-content/plugins/display-tweets-php" . Ensuite, insérez ce code sur la ligne 591, elle fonctionnera parfaitement.

if (is_array($tweets)){  
        foreach ( $tweets as $Tweet ) 
    {
        ...
    }
}
0
Saad Khanani