foreach()に無効な引数が指定されました


304

配列またはnull変数のいずれかである可能性のあるデータを処理foreachし、これらにこれらのデータを供給することがよくあります。

$values = get_values();

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

配列ではないデータをforeachに与えると、警告が表示されます。

警告:[...]のforeach()に無効な引数が指定されています

get_values()関数をリファクタリングして常に配列を返すことは不可能であると仮定すると(下位互換性、使用可能なソースコード、その他の理由)、これらの警告を回避する最もクリーンで最も効率的な方法はどれかと思います。

  • $values配列へのキャスト
  • $values配列への初期化
  • でラップforeachするif
  • その他(ご提案ください)

$values配列ではない可能性が高いです。
Bhargav Nanekalva 2017

回答:


509

個人的には、これが最もクリーンであることがわかります-それが最も効率的であるかどうかはわかりません!

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

私の好みの理由は、とにかく何もないときに空の配列を割り当てないからです。


4
または、count()を使用して、配列が空でないかどうかを調べます
Kemo

76
@Kemo:count()信頼できません。あなたが渡した場合count()はnullを、それはあなたがそれを渡す場合は0を返します。null以外は、非配列の引数は、それは1を返します。したがって、それは使用することは不可能だcount()、変数は空の配列することができたときに、変数が配列であるかどうかを判断したり、 1つの項目を含む配列。
アンディシェラム

12
一部のオブジェクトは反復可能であり、この回答はそれらを考慮していないことに注意してください。
Brad Koch

32
する必要がありますif (is_array($values) || $values instanceof Traversable)
Bob Stein

3
それは確かに最も効率的ではなかったと彼が続けなかったのは残念ですが、:D
グイプラ

116

これはどう?たくさんきれいになり、すべて一列に。

foreach ((array) $items as $item) {
 // ...
 }

7
これは私のために働いた唯一のものです。何らかの理由で、PHPは私が構築した多次元配列が実際には配列の配列であるとは信じていませんでした。
ジャスティン

1
ここでも同じですが、これは配列またはnull値のいずれかを含む配列に対する非常に優れた修正です。データがnullの場合に続行するには、foreachループにテストを追加するだけです。
Lizardx 2016年

私の問題を解決しました。ありがとう!
Hitesh

1
$ _POSTとチェックボックスを使用して配列とnone-array値のif、elseをスキップした素晴らしいコード!
Yann Chabot、2016年

2
注:美しく見え、無効な​​foreach警告が解決されますが、このメソッドは、変数が設定されていない場合、未定義の変数警告を返します。完全にシナリオなどに応じて、どちらisset()is_array()または両方を使用します
James

42

私は通常、次のような構成を使用します。

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

この特定のバージョンはテストされておらず、メモリから直接SOに入力されていることに注意してください。

編集:通過可能チェックを追加


3
ベストアンサー。ただし、本当に確認する必要があると思います$var instanceof Traversable。こちらをご覧ください。たとえば、SimpleXMLElementをforeachできますが、それはIteratorまたはIteratorAggregateのインスタンスではありません。
Bob Stein

2
他の2つのクラス@Krisを削除できる場合があります。どちらもTraversableを拡張しており、5.0.0でそのように生まれたようです。instanceofが常に適用されるかどうかについて、私は小さな疑問を感じています。
Bob Stein

1
@ BobStein-VisiBone:はい(ただし、クラスではなくインターフェースである場合を除く)ただし、私はそれらの前にTraversableを入れました、IteratorもIteratorAggregateも検証を必要としません(このようにして、実行が遅くなることはありません)。回答を元の回答にできるだけ近づけて、わかりやすく、読みやすくするために、それらを残しました。
クリス

2
is_object($var)re を追加するのは公平だと思います。php.net/manual/en/language.oop5.iterations.php
Mark Fox

1
@MarkFox:お気軽に。ただし、意図的に省略しました。Iteratorまたはを実装しても効果がなかった使用法を見たことがありませんIteratorAggregateが、それはもちろん私の意見であり、主観的なものです(私はパブリックフィールドを使用していません)。
クリス14

15

他の人がエラーを防ぐための有効なオプションとしてこれを提案している場合でも、別の問題を引き起こす可能性があるため、ソリューションとしてのキャストに依存しないでください

注意:特定の形式の配列が返されることが予想される場合、これは失敗する可能性があります。これにはさらにチェックが必要です。

たとえば、ブール値を配列にキャストしても、空の配列(array)boolにはなりませんが、ブール値をint:[0=>0]またはとして含む1つの要素を持つ配列になり[0=>1]ます。

私はこの問題を提示する簡単なテストを書きました。(これは、最初のテストURLが失敗した場合のバックアップテストです。)

:のためのテストです含めnullfalsetrueclassarrayとはundefined


foreachで使用する前に、必ず入力をテストしてください。提案:

  1. クイックタイプチェック$array = is_array($var) or is_object($var) ? $var : [] ;
  2. foreachを使用して戻り値の型指定する前に、メソッドにヒント配列入力する
  3. if内でforeachをラップする
  4. try{}catch(){}ブロックの使用
  5. 適切なコードの設計/製品版リリース前のテスト
  6. 正しい形式に対して配列をテストするarray_key_existsには、特定のキーで使用するか、配列の深さをテストします(それが1の場合!)
  7. 重複するコードを減らす方法で、常にヘルパーメソッドをグローバル名前空間に抽出します。

8

これを試して:

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

;)


1
これは連想配列ではうまく機能しません.. is_arrayメソッドは全体的に優れています...そして簡単です...
AO_

4
$values = get_values();

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

問題は常にnullであり、キャスティングは実際にはクリーニングソリューションです。


3

まず、すべての変数を初期化する必要があります。常に。
キャストはオプションではありません。
if get_values(); もちろん、異なるタイプの変数を返すことができますが、この値をチェックする必要があります。


キャストはオプションです-を使用し$array = (array)null;て配列を初期化すると、空の配列が取得されます。もちろん、それはメモリ割り当ての無駄です;-)
Andy Shellam

2
1:ビューの感傷的な観点からの読み取りは、私は言語がなくて行うことができた場合、変数は気にしないしなければならないと宣言することで信頼性の低い結果をしなければならないチェックすること。開発者を正気に保ち、エラーログを短くする必要があります。
クリス

3

@Krisのコードのより簡潔な拡張

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

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

特にテンプレートコード内で使用する場合

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

2
どういう意味return is_iterable($var) ? $var : array($var);ですか?
SQB 2015

3

php7を使用していて、未定義のエラーのみを処理したい場合、これは最もクリーンなIMHOです。

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}

2
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

これは配列かどうかはチェックしませんが、変数がnullまたは空の配列の場合はループをスキップします。


1

これが当てはまるかどうかはわかりませんが、ワードプレスサイトや一般的な動的サイトを移行するときに、この問題が何度も発生するようです。この場合は、移行先のホスティングで、古いサイトが使用しているものと同じバージョンのPHPを使用していることを確認してください。

サイトを移行しておらず、これが問題となっているだけの場合は、PHP 5に更新してみてください。これにより、これらの問題のいくつかが処理されます。ばかげた解決策のように見えるかもしれませんが、私のためにトリックをしました。


1

foreachループ内で配列をnullに設定すると、この通知の例外的なケースが発生します

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

1

このソリューションはどうですか:

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

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

1

foreach()表示ツイートに警告の無効な引数が指定されました。に行く/wp-content/plugins/display-tweets-php。次に、このコードを行番号591に挿入します。完全に実行されます。

if (is_array($tweets)) {
    foreach ($tweets as $tweet) 
    {
        ...
    }
}

驚くばかり!それは受け入れられる解決策であるべきです。私の場合、これを追加しました:if (is_array($_POST['auto'])){ // code }
Jodyshop

0

環境との関係もあるようです:

「無効な引数がforeach()で提供されました」というエラーが発生したのは、開発環境ではなく、prodではありませんでした(localhostではなくサーバーで作業しています)。

エラーにもかかわらず、var_dumpは、配列がそこにあることを示しました(どちらの場合もappとdev)。

if (is_array($array))周りのforeach ($array as $subarray)問題を解決しました。

申し訳ありませんが、原因を説明することはできませんが、解決策を見つけるのにしばらく時間がかかったので、これを観察としてよりよく共有することを考えました。


0

foreachループに配列を渡す場合は、is_array関数を使用します。

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

0

get_value()が空の場合、空の配列をフォールバックとして定義するのはどうですか?
最短の方法は考えられません。

$values = get_values() ?: [];

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

0

私はの組み合わせを使用しますemptyissetis_arrayのように

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

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

-3

アンディと同じことをしますが、「空」関数を使用します。

そのようです:

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
-1、$yourArray = 1;反復しようとすると、エラーが発生します。 empty()は適切なテストではありません。
Brad Koch

@BradKochは完全に正しいです。is_array()は、$ yourArrayが配列であるかどうかをテストする唯一の信頼できる方法です。is_array()では不十分な理由の詳細については、他の回答を参照してください。foreachは反復子も処理できます。
cgeisel 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.