365 votes

Argument non valide fourni pour foreach()

Il m'arrive souvent de manipuler des données qui peuvent être soit un tableau soit une variable nulle et d'alimenter des foreach avec ces données.

$values = get_values();

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

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

Attention : Invalid argument supplied for foreach() in [...]

En supposant qu'il n'est pas possible de refactoriser la get_values() pour qu'elle renvoie toujours un tableau (compatibilité ascendante, code source non disponible, ou toute autre raison), je me demande quelle est la manière la plus propre et la plus efficace d'éviter ces avertissements :

  • Casting $values vers le tableau
  • Initialisation de $values vers le tableau
  • Emballage de la foreach con un if
  • Autre (veuillez suggérer)

1 votes

Il est fort possible que le $values n'est pas un tableau.

591voto

Andy Shellam Points 8120

Personnellement, je trouve que c'est le plus propre - mais je ne suis pas sûr que ce soit le plus efficace !

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

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

4 votes

Ou utiliser count() pour savoir si le tableau n'est pas vide.

79 votes

@Kemo : count() n'est pas fiable. Si vous passez count() Si vous lui passez un argument qui n'est pas nul et qui n'est pas un tableau, il renvoie 1. Il est donc impossible d'utiliser count() pour déterminer si la variable est un tableau alors que la variable pourrait être un tableau vide, ou un tableau contenant 1 élément.

12 votes

Notez que certains objets sont itérables et que cette réponse n'en tient pas compte.

47voto

Kris Points 11892

J'utilise généralement une construction similaire à 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 a été tapée directement dans SO de mémoire.

Edit : ajouté Traversable vérifier

3 votes

Meilleure réponse. Sauf que je pense que vous devriez vraiment vérifier si $var instanceof Traversable . Voir aquí . Parce que, par exemple, vous pouvez effectuer un foreach sur un SimpleXMLElement mais il n'est pas une instance de Iterator ou de IteratorAggregate.

0 votes

@BobStein-VisiBone : Je suis tout à fait d'accord, ajouté.

2 votes

Vous pouvez peut-être supprimer les deux autres classes, @Kris. Elles étendent toutes deux Traversable et semblent être nés ainsi en 5.0.0. Bien que je ressente un petit doute quant à savoir si instanceof s'applique toujours aux extends.

12voto

Essayez ça :

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

;)

1 votes

Cela ne fonctionnera pas bien avec les tableaux associatifs... La méthode is_array est globalement meilleure... et plus facile...

5voto

Tout d'abord, chaque variable doit être initialisée. Toujours.
Le moulage n'est pas une option.
si get_values() ; peut retourner une variable de type différent, cette valeur doit être vérifiée, bien sûr.

0 votes

Le moulage est une option - si vous initialisez un tableau à l'aide de $array = (array)null; vous obtenez un tableau vide. Bien sûr, c'est un gaspillage d'allocation de mémoire ;-)

3 votes

+1 : lire d'un point de vue sentimental, peu importe si la langue peut s'en passer, variables MUST être déclarés et les résultats non fiables MUST être vérifié. C'est nécessaire pour que le ou les développeurs restent sains d'esprit et que les journaux d'erreurs soient courts.

0 votes

C'est loin dans le temps la meilleure réponse à cette question. Si vous essayez d'itérer quelque chose, vous vous attendez clairement à ce qu'il soit itérable. Faire un casting ou vérifier si elle est itérable est une perte de temps, car cela ne fait que masquer le fait que la variable ne contient pas ce que vous pensez qu'elle contient, ce qui signifie que la fonction réel Le problème est quelque part ailleurs dans votre code.

1voto

Erik Points 11

Je ne suis pas sûr que ce soit le cas mais ce problème semble se produire un certain nombre de fois lors de la migration de sites wordpress ou de sites dynamiques en général. Si c'est le cas, assurez-vous que l'hébergement vers lequel vous migrez utilise la même version de PHP que votre ancien site.

Si vous n'êtes pas en train de migrer votre site et qu'il s'agit simplement d'un problème, essayez de passer à PHP 5. Cela résout certains de ces problèmes. Cela peut sembler une solution stupide, mais cela a fonctionné pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X