テクノロジー

2023年2月2日

さまざまな制御構文

  • 複数の条件分岐の制御構文を知り、使えるようになる
  • 複数の繰り返しの制御構文を知り、使えるようになる
  • 掲示板アプリケーションのプログラムをわかりやすく整えることができる

条件分岐の制御構文

if 以外の条件分岐の制御構文の使い方を見ていきましょう

switch

switch を使用して、実行するコードの多くのブロックの1つを選択します。
switch の基本的な書き方は以下の通りです。

<?php
 
switch (比較する値) {
    case 値1:
        // 比較する値が値1と同じ場合の処理
        break;
    case 値2:
        // 比較する値が値2と同じ場合の処理
        break;
    default:
        // 比較する値がcaseで指定したどの値にも当てはまらない場合の処理
}

仕組みは次のとおりです。最初に、1回評価される単一の式 $n(ほとんどの場合変数)があります。次に、式の値が構造内の各 case の値と比較されます。一致するものがある場合、その case に関連付けられたコードのブロックが実行されます。break を使用して、コードが次のケースに自動的に実行されないようにします。一致するものが見つからない場合は、default が使用されます。

[例]

<?php
 
$favcourse = 'PHP';
 
switch ($favcourse) {
    case 'PHP':
        echo 'あなたの好きなコースはPHPです!' . PHP_EOL;
        break;
    case 'Ruby':
        echo 'あなたの好きなコースはRubyです!' . PHP_EOL;
        break;
    case 'Java':
        echo 'あなたの好きなコースはJavaです!' . PHP_EOL;
        break;
    default:
        echo 'お気に入りのコースは、Java、Ruby、またはPHPではありません。' . PHP_EOL;
}

[実行結果]

あなたの好きなコースはPHPです

switch は緩やかな比較であることに注意してください。

<?php
 
$foo = 0;
 
switch ($foo) {
    case false:
        echo '$foo is false' . PHP_EOL;
        break;
    case 0:
        echo '$foo is 0' . PHP_EOL;
        break;
    case null:
        echo '$foo is null' . PHP_EOL;
        break;
    default:
        echo 'default' . PHP_EOL;
}

$foo is 0 が出力されることを期待していますが、実際には$foo is falseが出力されます。
これはswitch の比較が緩やかな比較をしていることが原因です。
重大なバグの原因となる可能性があるので、どのように比較をしているのかを意識しましょう。

繰り返しの制御構文

while 以外の、繰り返しの制御構文の使い方を見ていきましょう。

forで繰り返す

for は、指定した回数だけ繰り返し処理を行います。
for の基本的な書き方は以下の通りです。

for 初期値 ; 条件式 ; 増減式{
  // 反復ごとに実行されるコード
}

処理が1回完了するごとに初期値の値を増減させ、条件式を満たす間、処理を繰り返します。
以下の例は、forを使って5までカウントアップするプログラムです。

[例]

<?php
 
for ($x = 0; $x <= 5; $x++) {
    echo $x . PHP_EOL;
}

[実行結果]

0
1
2
3
4
5

forEachで繰り返す

forEach は配列の各要素に対して反復処理を行う場合に便利な構文です。
forEach の構文は以下のように記述します。

forEach (配列 as 要素) {
    // 反復処理
}

実際に1から7の整数からなる配列からforEachを使って各要素を順に取り出し、echoで出力するという反復処理を行なってみます。

[例]

<?php
 
$arr = [1, 2, 3, 4, 5, 6, 7];
 
forEach ($arr as $value) {
    echo $value . PHP_EOL;
}

[実行結果]

1
2
3
4
5
6
7

各要素に対してechoで出力するという反復処理が実行できました。
なお、ループを抜けても $value には最後の要素である 7 が保持されたままの状態となり点に注意しましょう。

<?php
 
$arr = [1, 2, 3, 4, 5, 6, 7];
 
forEach ($arr as $value) {
    echo $value . PHP_EOL;
}
 
echo $value . PHP_EOL; // ループの外で$valueを出力する

[実行結果]

$ php sample.php
1
2
3
4
5
6
7
7

このように、ループを抜けても$valueは最後の$arr[6]への参照を保持したままの状態となります。
この参照を解除したい場合は、unset関数を使用します。

<?php
 
$arr = [1, 2, 3, 4, 5, 6, 7];
 
forEach ($arr as $value) {
    echo $value . PHP_EOL;
}
 
unset($value); // unset()で参照を解除できる
echo $value . PHP_EOL; // ループの外で$valueを出力する

[実行結果]

$ php sample.php
1
2
3
4
5
6
7
PHP Warning:  Undefined variable $value in /Users/diveintocode/programing/php/version/test/sample.php on line 10

Warning: Undefined variable $value in /Users/diveintocode/programing/php/version/test/sample.php on line 10

※エラーの際に表示されるパスは環境によって異なります。
参照が解除されたため、参照ができない旨のエラーが発生します。

また、以下のように記述することで、各要素のインデックスも取得できます。

forEach (配列 as インデックス => 要素) {
    // 反復処理
}

先ほどと同じ配列を使って各要素のインデックスも出力してみましょう。

<?php
 
$arr = [1, 2, 3, 4, 5, 6, 7];
 
forEach ($arr as $index => $value) {
    echo $index . ":" . $value . PHP_EOL;
}

[実行結果]

$ php sample.php
0:1
1:2
2:3
3:4
4:5
5:6
6:7

また、連想配列に対しても forEach が使用できます。

<?php
 
$arr = [
    'name'    => 'tanaka',
    'age'     => 30,
    'address' => 'Tokyo'
];
 
forEach ($arr as $key => $value) {
    echo $key . ': ' . $value . PHP_EOL;
}

[実行結果]

name: tanaka
age: 30
address: Tokyo

このように、キーと値を使った反復処理を実行できます。

繰り返し構文の中で使われる装飾子

break

break は、繰り返し処理を抜ける動きをするため、forforeachwhiledo-whileswitch などで使われます。

[例]

<?php
 
for ($x = 0; $x < 10; $x++) {
    if ($x === 4) {
        break;
    }
    echo "The number is: $x" . PHP_EOL;
}

[実行結果]

The number is: 0
The number is: 1
The number is: 2
The number is: 3

continue

continue は、指定された条件が発生した場合、(ループ内の)1つの反復を中断し、ループ内の次の反復を続行します。

[例]

<?php
 
for ($x = 0; $x < 10; $x++) {
    if ($x === 4) {
        continue;
    }
    echo "The number is: $x" . PHP_EOL;
}

continue や break はオプションで引数を渡すことができます。ループを抜けたりスキップする階層を指定できます。デフォルトは1です。

<?php
 
$i = 0;
while ($i++ < 5) {
    echo '外側の反復処理' . $i . '回目'. PHP_EOL;
    while (true) {
        echo '内側の反復処理' . $i . '回目' . PHP_EOL;
        continue 2; // 2階層目の反復処理をスキップ
    }
    echo '出力されないコメント' . PHP_EOL;
}

[実行結果]

外側の反復処理1回目
内側の反復処理1回目
外側の反復処理2回目
内側の反復処理2回目
外側の反復処理3回目
内側の反復処理3回目
外側の反復処理4回目
内側の反復処理4回目
外側の反復処理5回目
内側の反復処理5回目

内側のwhileではtrueを指定しているため、本来反復処理が永遠繰り返されるはずですが、continue 2;で2階層目の反復処理(while (true){ })をスキップさせることで処理が終了します。

掲示板アプリケーションのプログラムを改修しよう

ここまでで学習した演算子や制御構文を使い、掲示板アプリケーションのプログラムを改修しましょう。
以下のように要件を変更します。

プログラムの要件

  1. プログラムを起動したら何をしたいのか初めに決めるため、下記を出力して該当の数字を入力してもらう
    以下の中から、行う処理を選択してください
    1:評価ポイントとコメントを入力する
    2:今までの結果を確認する
    3:終了する
  2. 1が入力されたら、以下の処理をする
    2-1. “1から5で評価を入力してください”と出力する
    2-2. readline で入力された評価ポイント受け取る
    2-3. 1から5以外を入力されたら”1から5で入力してください”と出力
    2-4. readline で入力されたコメントを受け取る
    2-5. 受け取った評価ポイントとコメントをdata.txtに書き込む
  3. 2が入力されたら、”これまでの結果”と出力し、data.txtに書き込まれている過去の評価ポイントとコメントを”ポイント:○ コメント:○○○”という形で全件出力する
  4. 3が入力されたら”終了します”と出力してプログラムを終了する
  5. 1から3以外を入力されたら、”1から3を入力してください”と出力して1に戻る

前回までのコードは以下の通りです。
[sample.php]

<?php
 
while (true) {
    $point = intval(readline('1から5の数字で評価を入力してください。終了する場合は「6」を入力してください' . PHP_EOL));
 
    if ($point === 6) {
        echo '終了します' . PHP_EOL;
        break;
    } elseif ($point !== 0) {
        $comment = readline('コメントを入力してください' . PHP_EOL);
        $post = "ポイント: ${point} コメント: ${comment}" . PHP_EOL;
        echo $post . PHP_EOL;
 
        $file = fopen('data.txt', 'a');
        fwrite($file, $post);
        fclose($file);
 
        $fread_file = fopen('data.txt', 'r');
        while (($line = fgets($fread_file )) !== false) {
            echo $line;
        }
        fclose($fread_file);
    } else {
        echo '数字を入力してください' . PHP_EOL;
    }
}

1.起動したら何をしたいのかを決める処理を記載する

1から3の数字を入力させて、何をさせるのかを促す処理を実装します。
キーボードから値を入力させるようにするため、readline() を使います。

while (true) {
    echo '実施したい処理を選択してください' . PHP_EOL;
    echo '1:評価ポイントとコメントを入力する' . PHP_EOL;
    echo '2:今までの結果を確認する' . PHP_EOL;
    echo '3:終了する' . PHP_EOL;
    $num = intval(readline());
    // 省略
}

次に、入力した数字を見て処理を分けるコードを実装します。
入力された数字が1, 2, 3でマッチしたときにそれぞれの処理を行うようにするため、switch case を使って処理を分けるようにします。

// 省略
while (true) {
    echo '実施したい処理を選択してください' . PHP_EOL;
    echo '1:評価ポイントとコメントを入力する' . PHP_EOL;
    echo '2:今までの結果を確認する' . PHP_EOL;
    echo '3:終了する' . PHP_EOL;
    $num = intval(readline());
    switch ($num) {
        case 1:
            // 1が入力されたときの処理
            break;
        case 2:
            // 2が入力されたときの処理
            break;
        case 3:
            // 3が入力されたときの処理
            break;
        default:
            // 1~3以外が入力されたときの処理
    }
}
// 省略

2. 1が入力されたら、評価ポイントとコメントを入力し、ファイルに書き出す

1が入力された場合、評価ポイントとして1から5の数字を入力させる処理を実装します。
キーボードから値を入力させるようにするため、readline() を使います。

// 省略
switch ($num) {
    case 1:
        echo '1から5で評価を入力してください' . PHP_EOL;
        $point = intval(readline());
        break;
    case 2:
        // 2が入力されたときの処理
        break;
    case 3:
        // 3が入力されたときの処理
        break;
    default:
        // 1~3以外が入力されたときの処理
}
// 省略

次に、入力した評価ポイントの数字を見て処理を分ける準備を行います。
数字が1から5の範囲で入力された場合と、1から5以外を入力された場合で分けるようにするため、if - else を使い、以下のように条件分岐しましょう。

if (1から5以外が入力された場合) {
    echo '1から5で入力してください' . PHP_EOL;
else
    // 1から5が入力されたときの処理
}

if の条件式に入力された数字が1から5かどうかを判別するため、0以下または5より大きいという条件で、1から5以外が入力された場合の条件式を用意します。
演算子を使って0以下または5より大きいという条件式を表現するとどうなるでしょうか。考えて記述しましょう。

条件式ができたら、評価ポイントの数字を見て分岐する処理を実装します。
1から5以外が入力されたときは、”1から5で入力してください”と表示するようにします。

// 省略
switch ($num) {
    case 1:
        echo '1から5で評価を入力してください' . PHP_EOL;
        $point = intval(readline());
        if (1~5以外が入力された時(0以下または5より大きいという条件式{
            echo '1から5で入力してください' . PHP_EOL;
        } else {
            // 1~5が入力されたときの処理
        }
        break;
    case 2:
        // 2が入力されたときの処理
        break;
    case 3:
        // 3が入力されたときの処理
        break;
    default:
        // 1~3以外が入力されたときの処理
}
// 省略

次に、1から5で入力された場合の処理を実装します。
readline() で入力されたコメントを受け取り、受け取った評価ポイントとコメントを data.txt に書き込みます。
ここは前回までのコードがそのまま利用できそうです。
受け取った評価ポイントとコメントを data.txt に書き込んでいる箇所のコードを抽出し、1から5が入力された場合の処理に追記しましょう。

// 省略
switch ($num) {
    case 1:
        echo '1から5で評価を入力してください' . PHP_EOL;
        $point = intval(readline());
        if (1~5以外が入力された時(0以下または5より大きいという条件式{
            echo '1から5で入力してください' . PHP_EOL;
        } else {
            // 受け取った評価ポイントとコメントをdata.txtに書き込む処理を行なっているコード
        }
        break;
    case 2:
        // 2が入力されたときの処理
        break;
    case 3:
        // 3が入力されたときの処理
        break;
    default:
        // 1~3以外が入力されたときの処理
}
// 省略

3. 2が入力されたら、”これまでの結果”と出力する

今まで入力された評価ポイントとコメントを、ポイント:○ コメント:○○○ という形で全件出力させるようにします。
情報は data.txt に書き込まれているため、ファイルを開いて読み込む処理を実装します。
ここも前回までのコードがそのまま利用できそうなので、data.txt を開いて読み込んでいる箇所のコードを抽出し、2が入力されたときの処理に追記しましょう。

// 省略
switch ($num){
    case 1:
        // 省略
        break;
    case 2:
        // data.txtを開いて読み込む処理を行なっているコード
        break;
    case 3:
        // 3が入力されたときの処理
        break;
    default:
        // 1~3以外が入力されたときの処理
}
// 省略

4. 3が入力されたら”終了します”と出力してプログラムを終了する

処理を終了させるため、繰り返す処理を終了させる構文を実装しましょう。

// 省略
switch ($num) {
    case 1:
        // 省略
        break;
    case 2:
        // 省略
        break;
    case 3:
        echo '終了します' . PHP_EOL;
        // 繰り返す処理を終了させる構文
        break;
    default:
        // 1~3以外が入力されたときの処理
}
// 省略 

5. 1から3以外を入力されたら、1から3で入力してください と出力して1に戻る

1から3以外が入力された場合は、メッセージを出力し、再度入力させます。
while で繰り返し処理をしているため、メッセージの出力のみを実装します。

// 省略
switch ($num) {
    case 1:
        // 省略
        break;
    case 2:
        // 省略
        break;
    case 3:
        // 省略
        break;
    default:
        echo '1から3で入力してください' . PHP_EOL;
}
// 省略

これでプログラムの要件の実装は終わりました。
コードは完成しましたでしょうか。

解答コード

<?php
 
while (true) {
    echo '実施したい処理を選択してください' . PHP_EOL;
    echo '1:評価ポイントとコメントを入力する' . PHP_EOL;
    echo '2:今までの結果を確認する' . PHP_EOL;
    echo '3:終了する' . PHP_EOL;
    $num = intval(readline());
    switch ($num) {
        case 1:
            $point = intval(readline('1から5で評価を入力してください' . PHP_EOL));
            if ($point <= 0 \\|\\| $point > 5) { // 0以下または5より大きいという条件式
                echo '1から5で入力してください' . PHP_EOL;
            } else {
                $comment = readline('コメントを入力してください' . PHP_EOL);
                $post = "ポイント: ${point} コメント: ${comment}" . PHP_EOL;
                echo $post . PHP_EOL;
                $file = fopen('data.txt', 'a');
                fwrite($file, $post);
                fclose($file);
            }
            break;
        case 2:
            echo 'これまでの結果' . PHP_EOL;
            $fread_file = fopen('data.txt', 'r');
            while (($line = fgets($fread_file )) !== false) {
                echo $line;
            }
            fclose($fread_file);
            break;
        case 3:
            echo '終了します' . PHP_EOL;
            break 2;
        default:
            echo '1から3で入力してください' . PHP_EOL;
    }
}

また、このままでは1から5以外の評価ポイントが入力された場合、”1から5で評価を入力してください”というメッセージが表示された後、最初の処理に戻ってしまいます。そこで、”1から5で評価を入力してください”というメッセージが表示された後、再度評価ポイントが入力できるようプログラムを改修しましょう。以下は解答例です。

解答コード

<?php
 
while (true) {
    echo '実施したい処理を選択してください' . PHP_EOL;
    echo '1:評価ポイントとコメントを入力する' . PHP_EOL;
    echo '2:今までの結果を確認する' . PHP_EOL;
    echo '3:終了する' . PHP_EOL;
    $num = intval(readline());
 
    switch ($num) {
        case 1:
            $point = intval(readline('1から5で評価を入力してください' . PHP_EOL));
            while (true) {
                if ($point <= 0 \\|\\| $point > 5) {
                    $point = intval(readline('1から5で入力してください' . PHP_EOL));
                } else {
                    $comment = readline('コメントを入力してください' . PHP_EOL);
                    $post = "ポイント: ${point} コメント: ${comment}" . PHP_EOL;
                    echo $post . PHP_EOL;
                    $file = fopen('data.txt', 'a');
                    fwrite($file, $post);
                    fclose($file);
                    break;
                }
            }
            break;
        case 2:
            echo 'これまでの結果' . PHP_EOL;
            $fread_file = fopen('data.txt', 'r');
            while (($line = fgets($fread_file )) !== false) {
                echo $line;
            }
            fclose($fread_file);
            break;
        case 3:
            echo '終了します' . PHP_EOL;
            break 2;
        default:
            echo '1から3で入力してください' . PHP_EOL;
    }
}

まとめ

繰り返しメソッドを使用する場合は、繰り返す処理をブロックの中に入れて使用する。

**- 条件分岐の制御構文には ifswitch がある。

  • 繰り返し制御構文には whileforforEach などが含まれます。処理を中断する break やプロセスを中断して続行する continue などのデコレータを使用できる。**

公式ドキュメント・参考情報

1. for
2. break
3. continue

ダイビックのことをもっと知ってみませんか?