PHPのfor文&怖い無限ループから脱出できるbreak/スキップできるcontinueWeb業界で働くためのPHP入門(7)(1/2 ページ)

オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。今回は、素数判定のロジックからbreak文やcontinue文の利点と使い方を解説。for文を使ったループ処理の基本とwhile文との違い、無限ループなども併せて紹介します【PHP 7.1含め2017年の情報に合うように更新】。

» 2017年06月26日 05時00分 公開

ループ中のbreak文

 オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載「Web業界で働くためのPHP入門」。

 前回の「PHPの算術演算子、インクリメント/デクリメント&whileを使ったループ処理/繰り返し文」では、while文による基本的なループについて解説しました。全てのループは前回の範囲のwhile文で書き表せますが、実際にはそれだけでは不便です。

 今回はループをよりスッキリと書き表すための構文について解説します。

 なお、PHP 7.1.6が2017年6月8日にリリースされています。本連載の範囲では特に影響はないと思いますが、幾つかバグフィックスされていますので、アップデートしておきましょう。

【お題】素数かどうか調べるロジックを考えてみよう

 ちょっと複雑なループの例として、素数かどうか調べるロジックを考えてみましょう。素数というのは、1と自分自身以外の数で割り切れない、1より大きい整数のことです。例えば、2、3、5、7、11などが素数になります。4は2で割り切れ、6は2または3で割り切れるため素数ではありません。

 素数かどうかの判定方法はいろいろありますが、最も単純な方法は、実際に割り切れる数があるかどうかを総当たりで探してみることです。割る数を2から始めてインクリメントするループを作り、割り切れる数があるかどうかを探すのです。割り切れるかどうかは、割ったときの余りを求める算術演算子「%」を使います。余りが0のときは割り切れるということです。

 まず、ここまでのロジックを実装してみます。素数かどうかを調べたい数値を$num変数に格納するものとすると、次のようになります。

<?php
$num = 15;  // 素数かどうかを調べたい数
$i = 2;
while($i < $num) {
    if ($num % $i == 0) {
        print($num."は素数ではありません<br>");
    }
    $i++;
}
print("素数判定が終了しました。");
リスト1 phplesson/chap07/checkPrimeNumber.php

 while文では$i変数をカウンターにして、2から$num未満までのループを作っています。5行目のif文では、$numを$iで割った余りを求め、0の場合は素数ではないという表示を行っています。この例の$numは15ですから素数ではありません。この表示が行われることが期待できます。それでは実行してみましょう。実行結果は以下のようになります。

15は素数ではありません
15は素数ではありません
素数判定が終了しました。

 2回表示されてしまいました。15は$iが3と5のときに割り切れるため、ループ中のその2回でprint文が実行されたためです。これでは、いまいちですね。

 表示1回目の3で割り切れた時点で素数ではないので、その先のループを実行する必要はありません。つまり途中でループから抜けたいわけです。

switch文だけではなく、ループ処理からも抜けられるbreak文

 こういった目的のために、break文があります。break文はswitch文から抜ける目的で使いましたが、それと同様にwhile文からも抜けることができます。

 では、リスト1にbreak文を追加して、割り切れた場合は表示を行った後、whileループから抜けることにしましょう。

<?php
$num = 15;
$i = 2;
while($i < $num) {
    if ($num % $i == 0) {
        print($num."は素数ではありません<br>");
        break;  // 【1】
    }
    $i++;
}
print("素数判定が終了しました。");
リスト2 phplesson/chap07/checkPrimeNumberWithBreak.php

 【1】が追加したbreak文です。

 これを実行すると、以下のようになります。

15は素数ではありません
素数判定が終了しました。

 ちゃんと1行だけ表示されるようになりました。

$numが素数だった場合

 次に、$numが素数だった場合を考えてみます。その場合は、「素数判定が終了しました。」としか表示されなくなってしまいます。素数の場合には、「〇〇は素数です。」という表示もするように改造してみましょう。

 この場合は最後のループまで実行されるため、カウンターの$iは$numと等しい値になっているはずです。そこでwhile文の後にその条件分岐を付け加えます。同時に、$numを固定値ではなく、2〜20の乱数を使うことにしましょう。

<?php
$num = rand(2, 20);
$i = 2;
while($i < $num) {
    if ($num % $i == 0) {
        print($num."は素数ではありません<br>");
        break;
    }
    $i++;
}
if($i == $num) {
    print($num."は素数です。<br>");
}
print("素数判定が終了しました。");
リスト3 phplesson/chap07/checkPrimeNumberWithRand.php

 乱数を使うので、実行するたびに結果が変わりますが、ここでは、素数の場合の結果を掲載しておきましょう。

7は素数です。
素数判定が終了しました。

 何度か実行して、結果を確認してみてください。

break文+整数で抜けるループの指定

 次に、2〜100の全ての整数について素数判定をすることを考えてみましょう。上記の例をさらにループで囲んでネストすれば実装できます。$numをカウンターにして2から100まで実行するだけです。

<?php
$num = 2;
while($num <= 100) {
    $i = 2;
    while($i < $num) {
        if ($num % $i == 0) {
            print($num."は素数ではありません<br>");
            break;
        }
        $i++;
    }
    if($i == $num) {
        print($num."は素数です。<br>");
    }
    $num++;
}
print("素数判定が終了しました。");
リスト4 phplesson/chap07/checkPrimeNumberBetween2And100.php

 インデントが1段深くなっていますが、4〜14行目はリスト3と同じものです。実行結果は以下のようになります。長いので途中を省略しています。

2は素数です。
3は素数です。
4は素数ではありません
5は素数です。
6は素数ではありません
〜省略〜
99は素数ではありません
100は素数ではありません
素数判定が終了しました。

 100までの範囲にある素数は、Wikipediaの素数のページに載っていますので、この結果が正しいか確認してみましょう。

 この例ではwhile文がネストして2重になっています。こうなると8行目のbreak文はどちらのwhileループから脱出するのだろうか、という疑問が生じるかもしれません。

 break文は、そのbreak文から見て最も内側のwhile文から脱出するようになっています。従って、この場合は意図した通りに動作します。

 仮に、素数ではない最初の数が見つかった時点で$numのループを終了したいとすると、内側ではなく外側のループから脱出しなければなりません。このような場合、break文にどのループを抜けるかを指定します。指定は何段目のループを抜けたいのかを整数で表記します。そのbreak文から見て最も内側のループを1段目と数え、そのすぐ外側のループであれば2となります。「break」は「break 1」と同等です。

 では、外側のループ、つまり、「break 2」を行うようなソースコードを記述してみましょう。

<?php
$num = 2;
while($num <= 100) {
    $i = 2;
    while($i < $num) {
        if ($num % $i == 0) {
            print($num."は素数ではありません<br>");
            break 2;  // 【1】
        }
        $i++;
    }
    if($i == $num) {
        print($num."は素数です。<br>");
    }
    $num++;
}
print("素数判定が終了しました。");
リスト5 phplesson/chap07/checkPrimeNumberWithBreak2.php

 先ほどのリスト4から変わったところは【1】のみです。これを実行すると、以下のようになります。

2は素数です。
3は素数です。
4は素数ではありません
素数判定が終了しました。

 $numが4のときに8行目で外側のループからも抜けているのが分かると思います。

       1|2 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。