[PHP]continueとは?現在の繰り返しだけをスキップする方法を徹底解説

PHP

はじめに

前回の記事では、ループや switch を即座に終了させる break を解説し、その対として度々登場していたのが今回取り上げる continue です。

continue は、break のようにループ全体を終了させるのではなく、現在の繰り返し(イテレーション)だけをその場でスキップし、次の繰り返しに進むための制御構文です。「特定の条件に合致する要素だけは処理をスキップしたいが、ループ自体は最後まで続けたい」という場面で活躍します。break と並んで break n; のような数値引数による階層指定も可能で、ネストしたループの制御にも使われます。本記事では基本的な使い方から、break との違い、実践的な活用例まで詳しく解説します。


構文概要

項目内容
構文名continue
種別制御構造(言語構文)
基本構文continue; または continue n;(nは対象とするループの階層数)
対象while、do-while、for、foreach
使用場所ループのブロック内でのみ有効
switch内での注意点switch内のcontinueはbreakと同じ意味になる(後述)
対応バージョンPHP 4以前から存在する最古参の構文の一つ

continueの動作(イメージ図)

  for ($i = 0; $i < 5; $i++) {
      if ($i === 2) {
          continue;   ← この回だけスキップし、$i++へジャンプする
      }
      echo $i;
  }
              │
              ▼
  出力: 0, 1, 3, 4
  ($i === 2 の時だけechoがスキップされるが、
   ループ自体は最後まで継続される)

ポイントは、continue がループを終了させるのではなく、その回の残りの処理だけを飛ばして、次の繰り返しへ進むという点です。for ループの場合、continue が実行されると、ブロック内の残りの処理はスキップされますが、更新式($i++など)は通常通り実行されてからループが継続します。


実践サンプル7選

例1:基本的な使い方

<?php

for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 !== 0) {
        continue; // 奇数はスキップする
    }
    echo "偶数: {$i}" . PHP_EOL;
}

例2:配列をフィルタリングしながら処理する

<?php

$users = [
    ['name' => '太郎', 'active' => true],
    ['name' => '花子', 'active' => false],
    ['name' => '次郎', 'active' => true],
];

foreach ($users as $user) {
    if (!$user['active']) {
        continue; // 非アクティブなユーザーは処理対象から除外する
    }
    echo "{$user['name']}さんにメールを送信します" . PHP_EOL;
}

例3:continueを使った早期スキップによるネストの回避

<?php

function processOrder(array $order): void
{
    /**
     * else句で処理を囲む代わりに、
     * 条件に合わなければ即座にcontinueする(ガード節的な活用)
     */
    foreach ($order['items'] as $item) {
        if ($item['quantity'] <= 0) {
            echo "{$item['name']}: 数量が0以下のためスキップ" . PHP_EOL;
            continue;
        }

        if ($item['price'] < 0) {
            echo "{$item['name']}: 価格が不正のためスキップ" . PHP_EOL;
            continue;
        }

        $subtotal = $item['quantity'] * $item['price'];
        echo "{$item['name']}: 小計 {$subtotal}円" . PHP_EOL;
    }
}

processOrder(['items' => [
    ['name' => 'ペン', 'quantity' => 3, 'price' => 100],
    ['name' => 'ノート', 'quantity' => 0, 'price' => 200],
]]);

例4:ネストしたループでの数値引数による階層指定

<?php

$matrix = [[1, -2, 3], [4, 5, -6], [7, 8, 9]];

foreach ($matrix as $rowIndex => $row) {
    foreach ($row as $value) {
        if ($value < 0) {
            // continue 2 とすることで、内側のループだけでなく
            // 外側のforeachの次の繰り返しへ直接進む
            echo "行{$rowIndex}に負の値があるためスキップします" . PHP_EOL;
            continue 2;
        }
        echo "処理中: {$value}" . PHP_EOL;
    }
}

例5:whileループでのcontinue使用時の注意点

<?php

$i = 0;

while ($i < 5) {
    $i++; // continueの前に更新処理を書く必要がある

    if ($i === 3) {
        continue; // ここでスキップしても、$i++は既に実行済み
    }

    echo "値: {$i}" . PHP_EOL;
}

例6:switch内でのcontinueの落とし穴(breakとの違い)

<?php

foreach ([1, 2, 3] as $i) {
    switch ($i) {
        case 2:
            /**
             * switch内でcontinueを使うと、PHPでは
             * break と同じ意味になる(switchを抜けるだけ)
             * ループの次の繰り返しへスキップしたい場合は
             * continue 2 と明示的に書く必要がある
             */
            continue; // これはswitchを抜けるだけで、foreachは継続する
        default:
            echo "処理: {$i}" . PHP_EOL;
    }
}

例7:CSVデータのヘッダー行をスキップして処理する

<?php

function processCsvLines(array $lines): array
{
    $results = [];

    foreach ($lines as $index => $line) {
        if ($index === 0) {
            continue; // 1行目(ヘッダー)は処理対象から除外する
        }

        $results[] = str_getcsv($line);
    }

    return $results;
}

print_r(processCsvLines(['name,age', '太郎,30', '花子,25']));

関連機能との比較

機能役割continueとの違い
continue現在の繰り返しをスキップし、次の繰り返しに進む本記事の対象。ループ自体は終了させない
breakループやswitchを即座に抜けるループ全体を終了させる点が、continueと大きく異なる(前回記事を参照)
return(関数内)関数の実行を終了し、値を返すループを含む関数全体の処理を終える、より強い制御構文
ガード節(早期リターン)条件に合致しない場合に処理を早期に終える設計パターン関数全体のレベルでの類似した発想。continueはループ内限定
条件式での除外if文で処理対象を絞り込むcontinueを使わず、処理内容全体をifブロックで包む代替アプローチ

よくある落とし穴(注意点)

  1. switch内のcontinueはbreakと同じ意味になる これが continue に関する最も有名で紛らわしい落とし穴です。switch がループの中にネストしている場合、switch 内で単に continue; と書いても、それは switch を抜けるだけ(break; と同じ効果)であり、外側のループの次の繰り返しへは進みません。意図した通りにループの繰り返しをスキップしたい場合は、continue 2; のように明示的に階層を指定する必要があります(例6を参照)。PHPはこの挙動について、バージョンによっては警告(Warning: "continue" targeting switch)を出すこともあります。
  2. forループでの更新式のタイミングを理解する for ループ内で continue を使うと、ブロック内の残りの処理はスキップされますが、for の更新式($i++など)は通常通り実行されてからループが継続します。while ループでは、更新処理をループ内のどこに書くかによって、continue 実行前にその処理が済んでいるかどうかが変わるため注意が必要です(例5を参照)。
  3. 数値引数の階層の数え方はbreakと同様 continue n; の n は、break n; と同じく「内側から数えて何階層分の繰り返しをスキップするか」を表します。深いネストでは、どの階層に影響するのかが分かりにくくなるため、過度な多用は避けましょう(例4を参照)。
  4. continueの乱用はロジックを追いにくくする 1つのループ内に continue が何度も登場すると、「結局このループは何を処理しているのか」が読み取りにくくなることがあります。各 continue の条件が独立した意味を持つ場合は問題ありませんが、複雑な条件分岐が絡む場合は、処理そのものを関数に切り出すことも検討しましょう(例3を参照)。
  5. continueと単純なifブロックのどちらが読みやすいかを検討する 「特定の条件の時だけ処理する」という単純なケースでは、continue でスキップするのではなく、処理全体を if ブロックで囲む方が分かりやすい場合もあります。状況に応じて、どちらがより自然に意図を表現できるかを考えましょう。

まとめ

観点まとめ
何をする構文か現在のループの繰り返しをその場でスキップし、次の繰り返しへ進む
主な用途条件に合致しない要素の除外、データのフィルタリング処理、ヘッダー行のスキップ
数値引数continue n;でネストしたループの、より外側の繰り返しをスキップできる
breakとの違いcontinueはループを継続、breakはループ全体を終了する
最重要の注意点switchがループ内にある場合、単純なcontinueはbreakと同じ意味になること

continue は、break と対をなす基本的なループ制御構文であり、特定の要素だけを処理対象から除外しながらループを継続したい場面で重宝します。switch との組み合わせにおける紛らわしい挙動にさえ注意すれば、データのフィルタリングや前処理のスキップなど、日常的なコーディングで安全に活用できる構文です。

タイトルとURLをコピーしました