PHP/条件分岐

出典: フリー教科書『ウィキブックス(Wikibooks)』
< PHP
ナビゲーションに移動 検索に移動

条件分岐[編集]

プログラミング言語は、丁度楽譜のように左から右、上から下に実行します。 しかし、PHPの最初の目的が静的なHTMLをサーバー側で動的に生成することだったことを思い出しましょう。

次の例は、時刻によって表示するメッセージを変えています。

時刻によって表示するメッセージを変える例
<?php $hour = localtime(null, true)["tm_hour"]; ?>
<?php if ($hour < 6 or $hour > 17): ?>
<p>こんばんは。</p>
<?php elseif ($hour < 10): ?>
<p>おはようございます。</p>
<?php else: ?>
<p>こんにちは。</p>
<?php endif; ?>
実行結果(0時から6時までと17時から24時まで)
<p>こんばんは。</p>
実行結果(6時から10時まで)
<p>おはようございます。</p>
実行結果(それ以外は)
<p>こんにちは。</p>
このように、生成するHTMLを動的に変更する場合、if文などによる条件分岐が活躍します。

3つの分岐構文[編集]

PHPには、if, switch, match の3つの分岐構文があります。

if[編集]

PHPには、C風のifがあります。else ifの短縮構文があるほか、テキストに埋込むのに適した代替構文があります。

:

<?php
$n = NAN;

// 基本構文
if ($n < 0) {
    echo '$n < 0', PHP_EOL;
} elseif ($n > 0) {
    echo '$n > 0', PHP_EOL;
} elseif ($n == 0) {
    echo '$n < 0', PHP_EOL;
} else {
    echo $n, PHP_EOL;
}
echo PHP_EOL;

// 代替構文
if ($n < 0):
    echo '$n < 0', PHP_EOL;
elseif ($n > 0):
    echo '$n > 0', PHP_EOL;
elseif ($n == 0):
    echo '$n < 0', PHP_EOL;
else:
    echo $n, PHP_EOL;
endif;
?>

<?php if ($n < 0): ?>
<?= '$n < 0' ?>
<?php elseif ($n > 0): ?>
<?= '$n < 0' ?>
<?php elseif ($n == 0): ?>
<?= '$n == 0' ?>
<?php else: ?>
<?= $n ?>
<?php endif; ?>
基本構文
if ( 条件1 ) 文1 else if ( 条件式2 ) 文2 elseif ( 条件式3 ) 文3  else 
else ifelse ifのシノニムでそれぞれ0回以上繰り返せる。
else 文は省略可能。
代替構文
if ( 条件式1 ):
    文1
elseif ( 条件式2 ):
    文2
    
else:
    
endif;
代替構文ではelse ifは使えない
埋込構文
<?php if ( 条件1 ): ?>
テキスト1
<?php elseif ( 条件式2 ): ?>
テキスト2
<?php elseif ( 条件式3 ): ?>
テキスト3

<?php elseif ( 条件式n ): ?>
テキストn
<?php else: ?>
テキスト
<?php endif; ?>

switch[編集]

PHPには、C風のswitchがあり、フォールスルーの挙動などほとんど同じですが、case の式に定数式以外の式が使える他、文字列などの比較も「緩やかな比較」で行えます。

<?php
$s = "as";
switch ($s) {
    case "abstract":
        echo "KW_abstract", PHP_EOL;
        break;
    case "and":
        echo "KW_and", PHP_EOL;
        break;
    case "as":
        echo "KW_as", PHP_EOL;
        break;
    case "break":
        echo "KW_break", PHP_EOL;
        break;
    default:
        echo "Unknown";
}
echo PHP_EOL;

switch ($s) :
    case "abstract":
        echo "KW_abstract", PHP_EOL;
        break;
    case "and":
        echo "KW_and", PHP_EOL;
        break;
    case "as":
        echo "KW_as", PHP_EOL;
        break;
    case "break":
        echo "KW_break", PHP_EOL;
        break;
    default:
        echo "Unknown";
endswitch;
?>

<?php switch ($s) : ?>
<?php case "abstract":?>
<?= "KW_abstract", PHP_EOL;?>
<?php break;?>
<?php case "and":?>
<?= "KW_and", PHP_EOL;?>
<?php break;?>
<?php case "as":?>
<?= "KW_as", PHP_EOL;?>
<?php break;?>
<?php case "break":?>
<?= "KW_break", PHP_EOL;?>
<?php break;?>
<?php default:?>
<?= "Unknown";?>
<?php endswitch; ?>
実行結果
C風のswitchで、もしbreakがないと次のcase以降も実行します。
基本構文
switch (  ) {
  case 式1 : 文1
  case 式2 : 文2
      
  case 式n : 文n
  default   : 
}
代替構文
switch (  ) :
  case 式1 : 文1
  case 式2 : 文2
      
  case 式n : 文n
  default   : 
endswitch ;
埋込構文
<?php switch (  ) : ?>
<?php case 式1 : ?>
テキスト1
<?php case 式2 : ?>
テキスト2

<?php case 式n : ?>
テキストn
<?php default:?>
テキスト
<?php endswitch; ?>

match[編集]

PHPのmatchは、switchと似ていますが、文ではなく式なので値が取れるほか、比較には「厳密な比較」が使われます。

matchには、代替構文も埋込み構文もありません。

<?php
$s = "as";
echo match ($s) {
    "abstract" => "KW_abstract",
    "and" => "KW_and",
    "as" => "KW_as",
    default => "Unknown",
},
    PHP_EOL;
?>
#switchの例と同じロジックです。簡素にかけていますが、
連想配列を使った実装
<?php
$s = "as";
echo [
    "abstract" => "KW_abstract",
    "and" => "KW_and",
    "as" => "KW_as",
][$s] ?? "Unknown",
    PHP_EOL;
?>
と書いたほうがより簡素だと考えるひともいるでしょう。
また、=>の右には「式」が要求されるので、echoのようなコマンドは使えません。
厳密でない比較の使用
<?php
$age = 18;
echo "{$age}歳は",
    match (true) {
        $age < 1 => "乳児",
        $age < 6 => "幼児",
        $age < 18 => "少年",
        default => "成人",
    },
    "です。",
    PHP_EOL;
?>
こんな事もできます。
基本構文
代替構文
(ありません)
埋込構文
(ありません)

2つの比較演算子[編集]

if や while なでの条件式で、使われる比較演算子には2種類あります。

==
型を厳格には区別しない「緩やかな比較」
===
型を厳格に区別する「厳密な比較」

なお、=等号1個は単なる代入命令ですが条件式で使われると代入された値を真理値として評価されます。

緩やかな比較[編集]

==は、型を厳格には区別しない「緩やかな比較」演算子です。

<?php
$a = 1;

if ($a == 1) {
    echo "整数:", PHP_EOL;
    var_dump($a, 1) ;
}
if ($a == 1.0) {
    echo "浮動小数点数:", PHP_EOL;
    var_dump($a, 1.0) ;
}
if ($a == "1") {
    echo "文字列:", PHP_EOL;
    var_dump($a, "1") ;
}
?>
実行結果
整数:
int(1)
int(1)
浮動小数点数:
int(1)
float(1)
文字列:
int(1) 
string(1) "1"
すべて一致します。

厳密な比較[編集]

===は、型まで一致していることを要求する「厳密な比較」演算子です。

<?php
$a = 1;

if ($a === 1) {
    echo "整数:", PHP_EOL;
    var_dump($a, 1) ;
}
if ($a === 1.0) {
    echo "浮動小数点数:", PHP_EOL;
    var_dump($a, 1.0) ;
}
if ($a === "1") {
    echo "文字列:", PHP_EOL;
    var_dump($a, "1") ;
}
?>
実行結果
整数:
int(1) 
int(1)
型の一致は、数値であるだけでは不十分で、整数か浮動小数点数かは区別しています。

値または型の不一致演算子[編集]

!==は型まで一致していない、あるいは値が一致していないと真をかえす演算子です。

条件分岐以外の話題[編集]

シンプルでダーティーなログインフォーム[編集]

login.php
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>シンプルでダーティーなログインフォーム</title>
  </head>
  <body>
<?php ?>
<?php if (!array_key_exists('username', $_POST)): ?>
<!-- GET Method -->
    <form action="login.php" method="POST"">
      <div><label for="username">ユーザー名:</label><input type="text" name="username" id="username"></div>
      <div><label for="password">パスワード:</label><input type="password" name="password" id="password"></div>
      <input type="submit" value="ログイン">
    </form>
<?php elseif ($_POST['username'] == "UserID" && $_POST['password'] == "PassWord" ): ?>
<!-- POST Method -->
    <p>ログイン成功</p>
<?php else: ?>
<!-- POST Method -->
    <p>ユーザー名 または パスワード が違います。<p>
<?php endif; ?>
  </body>
</html>
このスクリプトは、ファーム入力とフォームの両方が含まれており
分岐コード
<?php if (!array_key_exists('username', $_POST)): ?>
スーパーグローバル変数 $_POST が(間違っていないかではなく)あるのかをテストして、なければGETメソッドと判断しています。
GETメソッドならばフォーム
<!-- GET Method -->
    <form action="index.php" method="POST"">
      <div><label for="username">ユーザー名:</label><input type="text" name="username" id="username"></div>
      <div><label for="password">パスワード:</label><input type="password" name="password" id="password"></div>
      <input type="submit" value="ログイン">
    </form>
を生成します。
POSTメソッドならば
ユーザー名とパスワードの両方が一致したら
<!-- POST Method -->
    <p>ログイン成功</p>
を生成します。
片方でも一致しなければ
<!-- POST Method -->
    <p>ユーザー名 または パスワード が違います。<p>
を生成します。
(ここでどちらが不一致だったかを教えてはいけません。ブルートフォース攻撃が格段に易しくなります。)
ファームのレンダリング例
ユーザー名:         
パスワード:         
登録


どこがダーティーか?[編集]

このコードには以下のような欠点があり、アジャイルにはともかく実務には使えません。

スクリプトに認証情報がハードコードされている
サーバーに侵入されなければ、JavaScript のように丸見えにはなりませんが「サーバーに侵入されない」前提で認証関係のコードを書いてはいけません。
メソッドを拠り所にフォームと認証を切り替えている
細工したユーザーエージェントからならば、メソッドを自由に切替えてチャレンジできます。
チャレンジ回数に限界がない
ブルートフォース攻撃に遭った時に、回数制限がないのは致命的な欠点です。

セッション管理[編集]

PHPは、基本機能としてセッション管理機能を提供しています(認証機能ではありません)。

session_example.php
<?php session_start(); ?>
<!DOCTYPE html>
<html>
  <head><title>PHP TEST</title></head>
  <body>
<?php if (!isset($_COOKIE["PHPSESSID"])): ?>
    <p>初回訪問: セッションを開始しました。</p>
<?php else: ?>
    <p>すでにセッションは始まっています。<p>
    <p>セッションIDは、<?= $_COOKIE["PHPSESSID"]; ?> です。<p>
<?php endif; ?>
  </body>
</html>


列挙型[編集]