はじめに
これまでの記事で、while・do-while・for・foreach という4つのループ構文、そして switch を解説してきましたが、その多くの実践例で既に登場していたのが、今回取り上げる break です。
break は、現在実行中のループ(while、do-while、for、foreach)や switch 文を、その場で即座に中断して抜けるための制御構文です。「特定の条件を満たしたら、それ以上繰り返す必要がない」という場面で、コードを無駄に実行し続けることを防ぎ、処理の意図を明確に表現できます。また、ネストしたループを複数階層まとめて抜ける際に使う、数値引数を使った応用的な書き方もあります。本記事では基本的な使い方から、continue との違い、実践的な活用例まで詳しく解説します。
構文概要
| 項目 | 内容 |
|---|---|
| 構文名 | break |
| 種別 | 制御構造(言語構文) |
| 基本構文 | break; または break n;(nは抜けるループの階層数) |
| 対象 | while、do-while、for、foreach、switch |
| 使用場所 | ループまたはswitchのブロック内でのみ有効 |
| 数値引数 | ネストしたループを複数階層まとめて抜ける際に指定する(デフォルトは1) |
| 対応バージョン | PHP 4以前から存在する最古参の構文の一つ |
breakの動作(イメージ図)
for ($i = 0; $i < 10; $i++) {
if ($i === 3) {
break; ← ここでforループ全体を即座に抜ける
}
echo $i;
}
echo 'ループ終了後の処理';
│
▼
出力: 0, 1, 2, "ループ終了後の処理"
($i === 3 になった時点で、残りの繰り返し(3〜9)は
一切実行されず、ループの次の行に処理が移る)
ポイントは、break がループ全体を即座に終了させるという点です。条件を満たした時点でそれ以降の繰り返しは一切行われず、制御はループの直後の行に移ります。
実践サンプル7選
例1:基本的な使い方
<?php
for ($i = 0; $i < 10; $i++) {
if ($i === 5) {
break;
}
echo "カウント: {$i}" . PHP_EOL;
}
echo 'ループを終了しました' . PHP_EOL;
例2:配列から目的の要素を見つけたら検索を打ち切る
<?php
$users = [
['id' => 1, 'name' => '太郎'],
['id' => 2, 'name' => '花子'],
['id' => 3, 'name' => '次郎'],
];
$foundUser = null;
foreach ($users as $user) {
if ($user['id'] === 2) {
$foundUser = $user;
break; // 見つかったら、残りの要素をチェックする必要はない
}
}
print_r($foundUser);
例3:switch内でのbreakの役割の再確認
<?php
function describeStatus(string $status): string
{
switch ($status) {
case 'active':
$result = '稼働中';
break; // breakがないと次のcaseにフォールスルーしてしまう
case 'inactive':
$result = '停止中';
break;
default:
$result = '不明';
}
return $result;
}
echo describeStatus('active') . PHP_EOL;
例4:ネストしたループを複数階層まとめて抜ける
<?php
$matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
$target = 5;
$found = false;
foreach ($matrix as $rowIndex => $row) {
foreach ($row as $colIndex => $value) {
if ($value === $target) {
echo "発見: 行{$rowIndex}, 列{$colIndex}" . PHP_EOL;
$found = true;
break 2; // 内側と外側、両方のループを同時に抜ける
}
}
}
if (!$found) {
echo '見つかりませんでした' . PHP_EOL;
}
例5:無限ループ(while (true))からの脱出条件として
<?php
$attempts = 0;
/**
* あえて条件なしの無限ループとして開始し、
* 内部のbreakで終了条件を明示的に制御する設計パターン
*/
while (true) {
$attempts++;
echo "試行{$attempts}回目" . PHP_EOL;
if ($attempts >= 3) {
echo '最大試行回数に達しました' . PHP_EOL;
break;
}
}
例6:早期終了によるパフォーマンス最適化
<?php
function hasDuplicate(array $items): bool
{
$seen = [];
foreach ($items as $item) {
if (isset($seen[$item])) {
// 重複を見つけた時点で、残りの要素を確認する必要はない
return true; // この文脈ではreturnがbreakと同様の早期終了の役割を果たす
}
$seen[$item] = true;
}
return false;
}
var_dump(hasDuplicate(['a', 'b', 'c', 'b'])); // true('b'が重複した時点で判定を打ち切る)
例7:switch内でのネストしたループに対するbreakの階層指定
<?php
foreach ([1, 2, 3] as $i) {
switch ($i) {
case 2:
// switch内のbreak 1はswitch自体を抜けるだけで、
// 外側のforeachは継続される
echo "{$i}はケース2です" . PHP_EOL;
break;
default:
echo "{$i}はデフォルトケースです" . PHP_EOL;
if ($i === 3) {
break 2; // switchとforeachの両方を同時に抜ける
}
}
}
echo '処理完了' . PHP_EOL;
関連機能との比較
| 機能 | 役割 | breakとの違い |
|---|---|---|
break | ループやswitchを即座に抜ける | 本記事の対象。処理全体を終了させる |
continue | 現在の繰り返しだけをスキップし、次の繰り返しに進む | ループ自体は終了せず、継続する点が大きく異なる |
return | 関数・メソッドの実行を終了し、値を返す | ループだけでなく、関数全体を抜ける、より強い制御構文 |
exit / die | スクリプト全体の実行を終了する | ループや関数の範囲を超えて、プログラム全体を停止させる |
goto | 指定したラベルへ処理をジャンプする | より自由度が高いが、可読性を損ないやすいため限定的に使われる |
よくある落とし穴(注意点)
continueとの混同breakはループ「全体」を終了させますが、continueは現在の繰り返し「1回だけ」をスキップして次に進みます。この2つの役割を混同すると、意図と異なる挙動になります。- 数値引数(
break n;)の階層の数え方を誤るbreak 2;のように数値を指定する場合、その数値は「内側から数えて何階層抜けるか」を表します。ネストが深くなると、どのbreakがどの階層まで影響するのかが分かりにくくなるため、過度に深いネストでの多用は避け、必要であれば関数への切り出しを検討しましょう(例4・例7を参照)。 switch内のbreakとループのbreakを混同するswitchがforeachなどのループ内にネストしている場合、switch内で単にbreak;と書くと、それはswitch自体を抜けるだけであり、外側のループは継続します。外側のループまで一緒に抜けたい場合は、break 2;のように明示的に階層を指定する必要があります(例7を参照)。do-whileの条件式部分でのスコープに注意するdo { ... break; } while (条件);のようにbreakでループを抜けた場合、whileの条件式はそもそも評価されません。ループ終了後の処理が、条件の真偽に依存しない設計になっているか確認しましょう。- 関数内では
returnの方が意図が明確な場合もある 関数の中でループを使っていて、特定の条件が見つかった時点で関数自体の処理を終えたい場合、breakでループを抜けてから別途returnするよりも、直接returnする方がコードがシンプルになることがあります(例6を参照)。
まとめ
| 観点 | まとめ |
|---|---|
| 何をする構文か | 現在実行中のループまたはswitchを即座に中断し、その範囲の外側へ処理を移す |
| 主な用途 | 条件に合致した要素が見つかった時点での検索打ち切り、無限ループからの脱出 |
| 数値引数 | break n;でネストしたループを複数階層まとめて抜けられる |
continueとの違い | breakはループ全体を終了、continueは現在の繰り返しだけをスキップ |
| 注意点 | switchとループが入れ子の場合の階層指定、深いネストでの可読性低下 |
break は、ループや switch の処理を無駄なく打ち切るための、シンプルかつ強力な制御構文です。continue との役割の違いを正しく理解し、ネストが深くなる場合は数値引数の階層指定に注意しながら、意図の伝わりやすいコードを書いていきましょう。
