web-dev-qa-db-ger.com

Ungültiges Argument für foreach () angegeben

Oft passiert es mir, Daten zu behandeln, die entweder ein Array oder eine Nullvariable sein können, und einige foreach mit diesen Daten zu füttern.

$values = get_values();

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

Wenn Sie ein Foreach mit Daten versorgen, die kein Array sind, erhalten Sie eine Warnung:

Warnung: Ungültiges Argument für foreach () in [...]

Angenommen, es ist nicht möglich, die Funktion get_values() so umzuwandeln, dass immer ein Array zurückgegeben wird (Abwärtskompatibilität, nicht verfügbarer Quellcode, aus welchem ​​Grund auch immer), frage ich mich, auf welche Weise diese Warnungen am saubersten und effizientesten sind:

  • Umwandlung von $values in ein Array
  • $values in Array initialisieren
  • Umwickeln der foreach mit einer if
  • Sonstiges (bitte vorschlagen)
252
Roberto Aloi

Ich persönlich finde das am saubersten - nicht sicher, ob es am effizientesten ist, Verstand!

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

Der Grund für meine Präferenz ist, dass kein leeres Array zugewiesen wird, wenn Sie sowieso nichts zum Anfang haben.

442
Andy Shellam

Wie wäre es mit diesem? viel sauberer und alles in einer Zeile.

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

Ich verwende normalerweise ein ähnliches Konstrukt:

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

Beachten Sie, dass diese bestimmte Version nicht getestet wird, sondern direkt aus dem Speicher in SO eingegeben wird.

Edit: hinzugefügt Traversable check

39
Kris

Bitte verlassen Sie sich nicht auf das Casting als Lösung, Auch wenn andere dies als gültige Option zur Vermeidung eines Fehlers vorschlagen, kann dies zu einer anderen führen.

Achtung: Wenn Sie erwarten, dass eine bestimmte Form eines Arrays zurückgegeben wird, schlägt dies möglicherweise fehl. Dafür sind weitere Überprüfungen erforderlich.

Z.B. Wenn ein boolescher Wert in ein Array (array)bool umgewandelt wird, ergibt NICHT ein leeres Array, sondern ein Array mit einem Element, das den booleschen Wert als int enthält: [0=>0] oder [0=>1].

Ich habe einen Schnelltest geschrieben, um dieses Problem darzustellen . (Hier ist ein backup Test falls die erste Test-URL fehlschlägt.)

Eingeschlossen sind Tests für: null, false, true, eine class, eine array und undefined.


Testen Sie Ihre Eingabe immer, bevor Sie sie in foreach verwenden. Vorschläge: 

  1. Schnelle Typprüfung : $array = is_array($var) or is_object($var) ? $var : [] ;
  2. Tippe Arrays in Methoden vor der Verwendung von foreach und Angabe von Rückgabetypen
  3. Foreach innerhalb von if einwickeln
  4. try{}catch(){}-Blöcke verwenden
  5. Entwerfen des korrekten Codes/Tests vor Produktionsversionen
  6. Um ein Array mit der richtigen Form zu testen, können Sie array_key_exists für einen bestimmten Schlüssel verwenden, oder die Tiefe eines Arrays testen (wenn es eins ist!) .
  7. Extrahieren Sie Ihre Hilfsmethoden immer in den globalen Namespace, um doppelten Code zu reduzieren
13
AARTT

Versuche dies:

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

;)

$values = get_values();

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

Das Problem ist immer null und Casting ist tatsächlich die Reinigungslösung.

4
boctulus

Zunächst muss jede Variable initialisiert werden. Immer.
.__ Casting ist keine Option.
if get_values ​​(); andere Typvariablen zurückgeben können, muss dieser Wert natürlich geprüft werden.

3

Kürzere Erweiterung des Codes von @ Kris

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

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

besonders für die Verwendung von Template-Code 

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

Wenn Sie php7 verwenden und nur undefinierte Fehler behandeln möchten, ist dies der sauberste IMHO

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

Dies prüft nicht, ob es sich um ein Array handelt, überspringt jedoch die Schleife, wenn die Variable null oder ein leeres Array ist.

2
T30

Wie wäre es mit dieser Lösung:

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

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

Ich bin mir nicht sicher, ob dies der Fall ist, aber dieses Problem scheint beim Migrieren von wordpress Sites oder beim Migrieren dynamischer Sites im Allgemeinen mehrmals aufzutreten. Wenn dies der Fall ist, stellen Sie sicher, dass das Hosting, auf das Sie migrieren, dieselbe PHP Version verwendet, die Ihre alte Site verwendet.

Wenn Sie Ihre Site nicht migrieren und dies nur ein Problem ist, versuchen Sie, ein Update auf PHP 5 durchzuführen. Dies behebt einige dieser Probleme. Könnte wie eine dumme Lösung erscheinen, hat aber den Trick für mich getan.

1
Erik

Ausnahmefall für diese Benachrichtigung tritt auf, wenn Sie das Array in der foreach-Schleife auf null setzen 

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

Was ist mit der Definition eines leeren Arrays als Fallback, wenn get_value() leer ist?
Ich kann mir keinen kürzesten Weg vorstellen.

$values = get_values() ?: [];

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

Ich benutze eine Kombination aus empty, isset und is_array als

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

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

Es scheint auch einen Bezug zur Umwelt zu geben:

Ich hatte den Fehler "ungültiges Argument für foreach ()" nur in der dev-Umgebung, aber nicht in prod (ich arbeite auf dem Server, nicht localhost).

Trotz des Fehlers zeigte ein var_dump an, dass das Array gut vorhanden war (in beiden Fällen app und dev).

Die if (is_array($array)) um die foreach ($array as $subarray) hat das Problem gelöst.

Tut mir leid, dass ich die Ursache nicht erklären kann, aber da ich eine Weile brauchte, um eine Lösung zu finden, dachte ich mir, dies als Beobachtung zu teilen.

0
araldh

Verwenden Sie die Funktion is_array, wenn Sie das Array an die foreach-Schleife übergeben.

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

Warnung ungültiges Argument für foreach () display tweets angegeben . Gehe zu "/ wp-content/plugins/display-tweets-php" . Dann füge diesen Code in Zeilennummer 591 ein.

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