タイトル: 繰り返し処理
SEOタイトル: PHP 繰り返し処理完全ガイド (for/foreach/while/array_map)
| この記事の要点 |
|
PHP のループ 4 種
foreach 構文の 2 形式
90, 'Bob' => 80, 'Carol' => 70];
// 形式1: value のみ
foreach ($scores as $score) {
echo $score, "\n"; // 90, 80, 70
}
// 形式2: key => value
foreach ($scores as $name => $score) {
echo "$name : $score\n"; // Alice : 90 ...
}
// ★ 参照渡し ($value への代入で配列本体を書き換え)
foreach ($scores as &$score) {
$score += 10;
}
unset($score); // ★ 必須: 参照を解除しないと次のループでバグる
print_r($scores); // 100, 90, 80
foreach の参照渡しの罠
break / continue / 多重ループ
関数型: array_map / array_filter / array_reduce
$n * 2, $nums);
// → [2, 4, 6, 8, 10]
// array_filter : 条件で抜き出す
$even = array_filter($nums, fn($n) => $n % 2 === 0);
// → [1 => 2, 3 => 4] ★ キーが保持される (再番号化したいなら array_values)
// array_reduce : 集約
$sum = array_reduce($nums, fn($acc, $n) => $acc + $n, 0);
// → 15
// array_walk : 参照渡しで全要素を変更 (戻り値は bool)
array_walk($nums, function (&$v, $k) { $v *= 10; });
// → $nums = [10, 20, 30, 40, 50]
// 連鎖: filter → map → reduce
$total = array_reduce(
array_map(fn($n) => $n * 2,
array_filter($nums, fn($n) => $n > 2)
),
fn($acc, $n) => $acc + $n,
0
); // (3+4+5)*2 = 24
Generators (yield) — 遅延評価ループ
巨大データを全部メモリに乗せたくないとき、yield で 1 件ずつ生成する Generator が便利です。
value 生成
function user_iter(): Generator {
yield 'alice' => 90;
yield 'bob' => 80;
}
foreach (user_iter() as $name => $score) { ... }
PHP 8 の match 式
'進行中',
3 => '完了',
default => '?',
};
// 条件式も書ける
$grade = match (true) {
$score >= 90 => 'A',
$score >= 70 => 'B',
$score >= 50 => 'C',
default => 'F',
};
無限ループ防止
= $max) {
throw new RuntimeException('Loop guard exceeded');
}
// PHP 設定でも防御
// php.ini : max_execution_time = 30 → 30 秒で fatal
性能比較 (10 万件処理の例)
| 方式 | 速度 | メモリ | 用途 |
|---|---|---|---|
foreach (値) | ★★★ 最速 | 少 | 定番 |
foreach (参照 &) | ★★★ | 少 | 要素書き換え |
for + $arr[$i] | ★★ やや遅 | 少 | index 必須 |
array_map | ★★ 関数呼び出しコスト | 中 (新配列) | 不変な変換 |
Generator (yield) | ★ やや遅 | ★ 極小 | 巨大データ |
使い分けチートシート
- 配列を順に処理 →
foreach - index が必要、または個数ベースで回す →
for - 終了条件が動的・読み込みが続く間 →
while - 必ず 1 回は実行 (リトライ等) →
do-while - 配列を変換して新配列にしたい →
array_map - 絞り込みたい →
array_filter - 合計・最大等の集約 →
array_reduce - メモリ節約したい巨大データ → Generator (
yield)
FAQ
Q: foreach のキー $key はインデックスとは限らない?
A: 連想配列なら文字列キー、添字配列なら 0 始まり整数。array_values() で再番号化可能。
Q: foreach で要素削除したい
A: foreach 内で unset($arr[$key]) は可。ただし参照渡しと併用すると挙動が複雑。array_filter で別配列にする方が安全。
Q: 関数型 (array_map 等) と foreach、どちらを使う?
A: 不変な変換は array_map、副作用 (DB 保存等) を含むなら foreach。Closure オーバーヘッドで foreach のほうが若干速い。