タイトル: 繰り返し処理
SEOタイトル: PHP for / foreach / while の使い分けと無限ループ・多重ループ脱出
| この記事の要点 |
|
for 文の基本構文
= 0; $i--) {
echo $i;
}
// 2 ずつ
for ($i = 0; $i < 20; $i += 2) {
echo $i . " "; // 0 2 4 ... 18
}
// 浮動小数も可能 (誤差注意)
for ($x = 0.0; $x < 1.0; $x += 0.1) {
echo $x . "\n";
}
// 複数式 (カンマ区切り)
for ($i = 0, $j = 10; $i < $j; $i++, $j--) {
// 中央で交差したら終了
}
count() をループ条件で呼ぶ罠
foreach: 配列の標準
$fruit) {
echo "$i: $fruit\n";
}
// 連想配列
$user = ['name' => 'Alice', 'age' => 30, 'email' => 'a@example.com'];
foreach ($user as $key => $value) {
echo "$key => $value\n";
}
// 参照渡しで要素を直接更新
$nums = [1, 2, 3];
foreach ($nums as &$n) {
$n *= 2;
}
unset($n); // ★ 必ず参照を解除 (重要)
print_r($nums); // [2, 4, 6]
// ネストした foreach
$matrix = [[1,2,3], [4,5,6], [7,8,9]];
foreach ($matrix as $row) {
foreach ($row as $cell) {
echo $cell . " ";
}
echo "\n";
}
for vs foreach の使い分け
| 条件 | 推奨 | 理由 |
|---|---|---|
| 配列の全要素を順番に処理 | foreach | 意図が明確、高速 |
| キー(インデックス)を演算に使う | for | i+1 番目との比較などに便利 |
| 配列の途中まで / 途中から | for or array_slice + foreach | 柔軟性 |
| 数値範囲を扱う (回数指定) | for | 明示的 |
| 反復可能オブジェクト (Iterator) | foreach | 標準対応 |
| 無限ループ・条件次第で終了 | while | 条件が複雑な時に |
while / do-while
break / continue で制御
isAdmin()) {
$admin = $u;
break; // 最初の管理者で終了
}
}
// continue: 次のイテレーションへ
foreach ($scores as $s) {
if ($s < 0) continue; // 負の値はスキップ
$total += $s;
}
// break/continue にレベル指定 (PHP 独自)
foreach ($matrix as $row) {
foreach ($row as $cell) {
if ($cell === 'X') {
break 2; // ★ 2 重ループを一気に脱出
}
}
}
// 内側の continue 2 で外側の次イテレーションへ
foreach ($groups as $group) {
foreach ($group->items as $item) {
if ($item->skip) continue 2; // 外側のループの次の group へ
// ...
}
}
無限ループの書き方と回避
$maxIter) throw new RuntimeException('iteration limit');
// ...
}
foreach の参照渡し: ありがちなバグ
性能比較 (参考)
foreach > for
// 組み込み関数があるなら最優先
FAQ
Q: foreach 中に配列要素を削除したい
A: unset($arr[$key]) は foreach 中でも安全(コピー走査)。ただし挙動が直感的でないケースもあるため、新配列に欲しい要素を集める方法を推奨。
Q: 配列が大きくて foreach が遅い
A: ジェネレータ (yield) でメモリ節約。あるいは組み込み関数 (array_map / array_filter) を活用。
Q: 連想配列の特定キーから走査開始したい
A: array_search でキー位置を得て array_slice、あるいは foreach + flag 変数で開始制御。