Menu

PHPのforeach:キーと値、インデックス、参照渡し

foreach ($array as $value)は配列のすべての要素を順に処理し、foreach ($array as $key => $value)ならキーも取得できます。インデックスの取得、参照による値の変更とunset()の落とし穴、breakとcontinue、ネストした配列、foreachでのlist()、HTMLの組み立てを扱います。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

foreach ($array as $value)は、要素ごとに1回ブロックを実行し、$valueには現在の要素が入ります。キーも取得するにはforeach ($array as $key => $value)と書きます。

foreachはキーがどうであれどんな配列にも使え、カウンターを管理したり長さを確認したりする必要がありません。PHPでいちばんよく書くループです。

キーと値でループする

$key => $valueの名前は自由に選べます:$name => $age、$id => $user、$k => $v。リストではキーは位置0, 1, 2です。連想配列では、自分で定義した文字列のキーです。

最後のループは、よく驚かれる細かい点を示しています。"1"のように整数に見える文字列のキーは、整数の1として保存されます。"01"は正規の整数表記ではないので、文字列のままです。

foreachでインデックスを取得する

リストではキーがインデックスなので、foreach ($items as $i => $item)だけで十分です。連想配列には数値の位置がないので、カウンターを持ちます。最初や最後の要素だけ扱いを変えるには、キーをarray_key_first()やarray_key_last()と比較します。

最後のループは名前の間にカンマを出力し、最後の名前のあとには出力しません。まさにこの用途ならimplode(', ', array_keys($scores))のほうが短く書けます。array_key_last()による確認は、区切り文字が違うだけでなく、最後の回で別の処理が必要な場合のためのものです。

foreachで配列の値を変更する(参照渡し)

$valueはコピーです。これに代入しても配列は何も変わりません。配列を変えるには、&$valueで参照としてループするか、キーを使って書き戻します。

どちらも動きます。キーを使う方法はループのあとに隠れた状態が残らないので、こちらを好むチームも多くあります。配列を変えるのではなく新しい配列を作るなら、array_map()という選択肢もあります。

関連する疑問として、ループ中に要素を追加するとどうなるでしょうか。普通のforeachはループ開始時点の配列を順に処理するので、中で$prices[] = ...としても回数は増えません。参照のループは現在の配列を処理するので、新しい要素も処理します。

参照渡しのforeachとunset()の落とし穴

foreach ($arr as &$v)のあとも、変数$vは配列の最後の要素への参照のままです。あとで普通のループに同じ名前の$vを使うと、毎回その最後の要素に書き込まれます。実行して最後の項目を見てください。

2つ目のループは$letters[2]にA、次にB、最後に最後の要素自身の値を代入しますが、最後の回の時点でその位置にはすでにBが入っています。直し方は1行で、参照によるforeachの直後に必ずunset($v);を書きます。

foreachでのbreakとcontinue

breakはループを抜け、continueは次の要素に飛びます。よくあるのは検索のパターンで、必要なものが見つかるまでループし、見つかったらbreakして配列の残りを確認しないようにします。

ネストしたループでは、break 2で内側とその外側のループを抜け、continue 2で外側のループの次の回に進みます。

ネストした配列とlist()を使ったforeach

データの行は、配列の中の配列です。行をループしてから各行をループするか、配列の分割代入を使ってforeachの行で直接フィールドを取り出します。リストには[$a, $b]、連想配列の行には['key' => $var]を使います。list($a, $b)は[$a, $b]の古い書き方です。

[...] =構文については、要素の読み飛ばしやネストしたパターンも含め、分割代入のページで詳しく説明しています。

foreachでHTMLのリストや表を作る

テンプレートでは、foreach (...):とendforeach;のコロン形式でタグの間でもループを読みやすく保てます。このブロックは表を作り、列の見出しはリンクになっています。Pageタブで見出しをクリックすると、$_GET['sort']がセットされた状態で同じスクリプトがもう一度実行され、行が新しい順番で返ってきます。

このブロックには真似したい習慣が2つあります。URLから来たsortの値は、使う前に許可された列の一覧と照合しています。そして、ユーザーのテキストを含みうる値をHTMLに出力するときは、すべてhtmlspecialchars()を通しています。

null、空の配列、オブジェクトに対するforeach

空の配列は問題ありません。本体が実行されないだけです。null、文字列、数値はだめで、PHPは警告を表示してループを飛ばします。$tags = null; foreach ($tags as $tag)では次のように表示されます。

Warning: foreach() argument must be of type array|object, null given in /var/www/html/index.php on line 4

これがいちばんよく起きるのは、デコードしたJSONの任意の項目のように、ときどき欠けるデータです。??で空の配列にフォールバックしましょう。

foreach ($data['tags'] ?? [] as $tag) {
    echo $tag;
}

このメッセージにあるobjectは本当です。オブジェクトに対するforeachは、ループが実行される場所から見えるプロパティ(クラスの外ならpublicなもの)を、プロパティ名をキーとして順に処理します。IteratorやIteratorAggregateを実装したクラスとジェネレーターは、foreachに何を見せるかを自分で決めます。

foreach、for、array_mapの使い分け

使うもの使う場面
foreachキーの有無にかかわらず、すべての要素が欲しい。リストでも連想配列でも、どんな配列にも使える。
for数える(1から100まで、1つおきの要素)か、添字で隣の要素が必要($a[$i - 1])。for文を参照。
array_map()各要素を変換して新しい配列を作る。fnを使って1行で書くことが多い。
array_filter()テストに合格した要素だけを残す。

手早い判断方法:ループの本体が要素ごとに新しい値を計算するだけなら、array_map(fn($x) => $x * 2, $a)で1行で表せます。副作用がある(出力する、保存する、複数のものを同時に数える)か、breakが必要なら、foreachを書きましょう。

よくある質問

PHPのforeachでキーと値を取得するには?

=>の形を使います:foreach ($array as $key => $value) { echo "$key: $value"; }。普通のリストではキーはインデックス(0、1、2)で、連想配列では'name'のような文字列のキーです。

PHPのforeachでインデックスを取得するには?

リストなら、キーがそのままインデックスです:foreach ($items as $i => $item)。連想配列では自分でカウンターを持ちます。ループの前に$i = 0;とし、各回の最後で$i++します。最初や最後のキーはarray_key_first()とarray_key_last()でわかります。

PHPのforeachの中で配列の値を変更するには?

&で参照としてループします:foreach ($prices as &$price) { $price *= 2; } unset($price);。またはキーを使って書き戻します:foreach ($prices as $key => $price) { $prices[$key] = $price * 2; }。単に$price = ...とするとコピーが変わるだけです。

PHPのforeachを参照で回すと最後の要素が重複するのはなぜですか?

foreach ($arr as &$v)のあとも、$vは最後の要素への参照のままです。次にforeach ($arr as $v)を回すと、各値がその最後の位置に書き込まれるので、最後の要素は最後から2番目の値の繰り返しになります。参照のループの直後にunset($v);を呼んでください。

PHPでforeachループを抜けるには?

break;はすぐにループを止め、continue;は次の要素へ飛びます。ネストしたループでは、break 2;で内側と外側の両方のループを抜けます。

Coddyのプログラミング言語のイラスト

Coddyでコードを学ぼう

始める