# ch04 — 入れ子 foreach で全走査

Source: https://php-school.pages.dev/topics/array-multi/ch04-2d-foreach/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: 多次元配列
Level: L2

Reference (official): https://www.php.net/manual/ja/language.types.array.php

## 本文

# ch04 — 入れ子 foreach で全走査

## 概要

2 次元配列の **全要素** に同じ処理をかけたい時は、**foreach を入れ子** にする。外側の foreach で 1 行ずつ取り出し、その行 (= 1 次元配列) に対して内側の foreach で 1 マスずつ取り出す、という 2 段構造になる。`foreach ($table as $row) { foreach ($row as $cell) { ... } }` という形を覚えるだけで、添字を意識せずに全マスを処理できるようになる。

この書き方の利点は、**行数も列数も気にせず動く** こと。`for ($i = 0; $i < count($table); $i++)` と `for ($j = 0; $j < count($table[$i]); $j++)` の入れ子でも同じことができるが、長さの取り扱いを間違えやすい。foreach にしておけば「配列の中にあるものを全部処理する」が一文で表現でき、ジャグ配列 (行ごとに長さが違う) でも崩れない。

計算量は **行数 × 列数 (O(N×M))** で、行が増えても列が増えても比例して処理時間が伸びる。少ない要素ならまったく問題ないが、ch05 (表整形) / ch06 (行合計) / ch07 (列合計) など今後の章はすべてこの入れ子 foreach が骨格になる。**外側を `as $row`、内側を `as $cell` のように意味のある名前にする** と、何をしているか後から読み返しやすい。

## 学習目標

- 外側 `foreach` で行を、内側 `foreach` で各マスを取り出せる
- 添字を意識せずに 2 次元配列を全走査できる
- 入れ子 foreach の構造を読める

## 所要時間

スライド 4 分 + ドリル 1 問 = **10 分**

## ドリル

| no | 内容 |
|---|---|
| 01 | 3×3 配列を入れ子 foreach で 1 マス 1 行ずつ出力 |

## 採点

```bash
php scripts/grade.php topics/array-multi/ch04-2d-foreach/drill/01-flatten/
```

## 関連チャプター

- [`ch02-2d-access`](../ch02-2d-access/) — 添字でアクセスする書き方 (foreach の代わりに使う)
- [`ch05-table-print`](../ch05-table-print/) — 入れ子 foreach を使って表形式に整形出力する
- [`ch06-row-sum`](../ch06-row-sum/) — 入れ子 foreach で行ごとの合計を組み立てる

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 6 / Chapter 4
  目的: 入れ子 foreach で 2 次元配列の全マスを走査できるようにする
  扱わない: 表整形 (ch05) / 行・列合計 (ch06, ch07)
  読み上げ時間目安: 3 分半〜4 分
-->

# 入れ子 foreach で全走査

Lesson 6 / Chapter 4

---

## 外側 foreach で「1 行ずつ」取り出す

```php
<?php
$table = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];
foreach ($table as $row) {
    print_r($row);
}
```

- `foreach ($table as $row)` で 1 行分の配列が `$row` に入る
- `$row` 自体がまだ配列 (内側の `[1, 2, 3]` 等)
- もう 1 段 foreach すれば中の値を取り出せる

---

## 内側 foreach で「1 マスずつ」取り出す

```php
<?php
$table = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];
foreach ($table as $row) {
    foreach ($row as $value) {
        echo $value . "\n";
    }
}
```

実行結果:

```
1
2
3
4
5
6
7
8
9
```

- 外側 `$row` = 1 行分の配列
- 内側 `$value` = その行の 1 マスの値

---

## for ループとの違い

```php
// for 版 (添字を自分で回す)
for ($i = 0; $i < count($table); $i++) {
    for ($j = 0; $j < count($table[$i]); $j++) {
        echo $table[$i][$j] . "\n";
    }
}

// foreach 版 (添字を気にしない)
foreach ($table as $row) {
    foreach ($row as $value) {
        echo $value . "\n";
    }
}
```

- 添字が要らないなら `foreach` のほうが読みやすい
- 添字が要るなら `for` か `foreach ($arr as $i => $row)` を使う

---

## 行の区切りを入れたいなら

```php
<?php
foreach ($table as $row) {
    foreach ($row as $value) {
        echo $value . " ";
    }
    echo "\n";   // 行の終わりに改行
}
```

実行結果:

```
1 2 3
4 5 6
7 8 9
```

- 内側 foreach の **後ろ** で改行を入れると、表のように見える
- これは次の章 (ch05) で詳しく扱う

---

## このチャプターでできるようになること

✅ 外側 foreach で 1 行ずつ取り出せる
✅ 内側 foreach で 1 マスずつ値を取り出せる
✅ 入れ子 foreach で 2 次元配列を全走査できる
✅ for 版と foreach 版の使い分けが分かる

→ ドリルへ
