PHP 入門

PHP 比較演算子と論理演算子

比較演算子と論理演算子は、PHPスクリプトの実行フローを制御するための基礎となる要素です。これらを使用することで、値同士の関係性や複数の条件の真偽に基づき、スクリプト内で「意思決定」を行うことが可能になります。

1. 比較演算子

比較演算子は2つの値を比較し、ブーリアン(真偽値)の結果である true(真)または false(偽)をリターンします。これらの演算子は条件文の中核であり、特定の基準を満たしたときのみコードを実行させるために不可欠です。

1.1 等価(==)と全等(===)

PHPには、等価性をチェックするための主要な方法が2つあります:緩やかな比較 (==) と厳密な比較 (===) です。

緩やかな比較 (==): この演算子は比較を行う前に、必要に応じて暗黙の型変換 (Type Juggling) を実行します。2つの値のタイプが異なる場合、PHPはそれらを同じタイプに変換してから比較を試みます。

<?php
$num1 = 10;
$str1 = "10";
$bool1 = true;
$strBool = "true";

// 例1:整数 vs 文字列(暗黙の型変換が発生)
var_dump($num1 == $str1); // 出力:bool(true) - 文字列 "10" が整数 10 に変換される

// 例2:整数 vs ブーリアン(暗黙の型変換が発生)
var_dump($num1 == $bool1); // 出力:bool(false) - 10 は 1 ではない(true を整数に変換すると 1)

// 例3:文字列 vs ブーリアン(暗黙の型変換が発生)
var_dump($strBool == $bool1); // 出力:bool(true) - 空ではない文字列 "true" はブーリアンのコンテキストで true とみなされる
?>

最初の例では、整数 10 と文字列 "10" は「等しい(等価)」とみなされます。これはPHPが比較前に文字列 "10" を整数にキャストしたためです。

厳密な比較 (===): この演算子は、2つの値が等しく、かつデータタイプも同じであるかどうかをチェックします。型変換は一切行われません。多くの場合、予期せぬバグを防ぎ正確な比較を保証するために、厳密な比較を使用することが強く推奨されます。

<?php
$num2 = 20;
$str2 = "20";
$bool2 = true;
$intTrue = 1;

// 例1:整数 vs 文字列(タイプが異なる)
var_dump($num2 === $str2); // 出力:bool(false) - データタイプ(int vs string)が異なる

// 例2:整数 vs ブーリアン(タイプが異なる)
var_dump($num2 === $bool2); // 出力:bool(false) - データタイプ(int vs bool)が異なる

// 例3:整数 1 vs ブーリアン true(タイプが異なる)
var_dump($intTrue === $bool2); // 出力:bool(false) - データタイプ(int vs bool)が異なる
?>

=== を使用することで、PHPの自動型変換による意図しない挙動を防ぎ、「値」と「タイプ」の両方において絶対的な正確性を確保できます。

1.2 不一致

等価性と同様に、不一致をチェックする演算子にも緩やかな比較 (!= または <>) と厳密な比較 (!==) があります。

緩やかな不一致 (!= または <>): 型変換後の値が等しくない場合に true をリターンします。<>!= の別名であり、機能は全く同じです。

<?php
$valA = 5;
$valB = "5";
$valC = 7;

// 例1:整数 vs 文字列(緩やかな不一致)
var_dump($valA != $valB); // 出力:bool(false) - 5 == "5" が true なので、5 != "5" は false

// 例2:整数 vs 整数
var_dump($valA != $valC); // 出力:bool(true) - 5 は 7 と等しくない
?>

厳密な不一致 (!==): 2つの値が等しくないか、あるいはデータタイプが異なる場合に true をリターンします。

<?php
$valD = 100;
$valE = "100";
$valF = 101;

// 例1:整数 vs 文字列(厳密な不一致)
var_dump($valD !== $valE); // 出力:bool(true) - 値は同じに見えるが、データタイプが異なる

// 例2:整数 vs 整数(値が異なる)
var_dump($valD !== $valF); // 出力:bool(true) - 値自体が等しくない
?>

1.3 大なり・小なりおよび組み合わせ

これらの演算子は、数値の大きさを比較するために使用されます。

  • 大なり (>): 左辺が右辺より大きい場合に true をリターン。
  • 小なり (<): 左辺が右辺より小さい場合に true をリターン。
  • 大なりイコール (>=): 左辺が右辺より大きいか等しい場合に true をリターン。
  • 小なりイコール (<=): 左辺が右辺より小さいか等しい場合に true をリターン。
<?php
$score = 85;
$passingGrade = 70;
$maxScore = 100;

// 大なり
var_dump($score > $passingGrade); // 出力:bool(true) - 85 は 70 より大きい

// 小なり
var_dump($score < $passingGrade); // 出力:bool(false) - 85 は 70 より小さくない

// 大なりイコール
var_dump($score >= $passingGrade); // 出力:bool(true) - 85 は 70 以上
var_dump($passingGrade >= 70);    // 出力:bool(true) - 70 は 70 と等しい(条件を満たす)

// 小なりイコール
var_dump($score <= $maxScore);    // 出力:bool(true) - 85 は 100 以下
var_dump($score <= 85);           // 出力:bool(true) - 85 は 85 と等しい(条件を満たす)
?>

1.4 宇宙船演算子 (<=>)

宇宙船演算子 (<=>) は PHP 7 で導入された3方向比較演算子です。以下の値をリターンします:

  • 0:両辺が等しい場合。
  • 1:左辺の方が大きい場合。
  • -1:右辺の方が大きい場合。

この演算子は、ソート(並び替え)関数の記述や、2つの値の大小関係と等価性を同時に知る必要がある場合に非常に便利です。

<?php
$a = 5;
$b = 10;
$c = 5;

var_dump($a <=> $b); // 出力:int(-1) - $a は $b より小さいため
var_dump($b <=> $a); // 出力:int(1)  - $b は $a より大きいため
var_dump($a <=> $c); // 出力:int(0)  - $a と $c は等しいため

// 文字列もサポート(辞書順/アルファベット順で比較)
$strX = "apple";
$strY = "banana";
$strZ = "apple";

var_dump($strX <=> $strY); // 出力:int(-1) - 'a' は 'b' より前にあるため
var_dump($strY <=> $strX); // 出力:int(1)
var_dump($strX <=> $strZ); // 出ity:int(0)
?>

2. 論理演算子

論理演算子は、ブーリアン式を組み合わせたり、反転させたりするために使用されます。複数の比較結果の真偽を評価することで、より複雑な条件を構築できます。

2.1 論理積 (AND) 演算子 (&& および and)

AND 演算子は、すべてのオペランドが true である場合のみ true をリターンします。いずれか一つでも false であれば、結果は false になります。

  • 論理積 (&&): 最も一般的に使用される AND 演算子で、and よりも優先順位が高いです。
  • 論理積 (and): && よりも優先順位が低いです。通常の開発では、&& の使用が推奨されます。
<?php
$age = 25;
$isStudent = true;
$hasLicense = false;

// && を使用
// 条件:年齢が 18 から 30 の間、かつ学生である
var_dump($age >= 18 && $age <= 30 && $isStudent); // 出力:bool(true)
                                                 // (true && true && true) -> true

// 条件:年齢が 18 より大きい、かつ免許を持っている
var_dump($age > 18 && $hasLicense);              // 出力:bool(false)
                                                 // (true && false) -> false

// 'and' を使用(優先順位の差異に注意)
// $canVote = $age >= 18 and $hasLicense;
// 注意:上記の行では、代入演算子 '=' の優先順位が 'and' より高いため、$canVote には ($age >= 18) の結果が先に代入されます。

// 正しい使用方法(括弧が必要):
$canVote = ($age >= 18 and $hasLicense);
var_dump($canVote); // 出力:bool(false)
?>

優先順位の罠を避けるため、一般的な条件チェックには && を標準として使用することを強くお勧めします。

2.2 論理和 (OR) 演算子 (|| および or)

OR 演算子は、少なくとも一つのオペランドが true であれば true をリターンします。すべてのオペランドが false である場合のみ、結果は false になります。

  • 論理和 (||): 最も一般的な OR 演算子で、or よりも優先順位が高いです。
  • 論理和 (or): || よりも優先順位が低いです。
<?php
$temperature = 28;
$isRaining = false;
$isSunny = true;

// || を使用
// 条件:温度が 25 度を超えている、または雨が降っている
var_dump($temperature > 25 || $isRaining); // 出力:bool(true)
                                          // (true || false) -> true

// 条件:雨が降っている、または晴れている
var_dump($isRaining || $isSunny);         // 出力:bool(true)
                                          // (false || true) -> true

// 条件:温度が 0 度未満、または雨が降っている(どちらも満たさない)
var_dump($temperature < 0 || $isRaining); // 出力:bool(false)
                                          // (false || false) -> false
?>

ANDと同様に、通常は or よりも || を使用することが推奨されます。

2.3 排他的論理和 (XOR) 演算子 (xor)

XOR 演算子は、オペランドのうちいずれか一方のみtrue の場合に true をリターンします。両方が true、あるいは両方が false の場合は false となります。

<?php
$condition1 = true;
$condition2 = false;
$condition3 = true;

// 例1:真と偽が一つずつ
var_dump($condition1 xor $condition2); // 出力:bool(true)

// 例2:両方真
var_dump($condition1 xor $condition3); // 出力:bool(false)

// 例3:両方偽($age = 25 の場合、($age < 18) は false)
var_dump($condition2 xor ($age < 18)); // 出力:bool(false)
?>

2.4 論理否定 (NOT) 演算子 (!)

NOT 演算子(論理反転)は、オペランドのブーリアン値を反転させます。オペランドが true なら false に、false なら true に変換します。

<?php
$isLoggedIn = false;
$isAdmin = true;

// 例1:false を反転
var_dump(!$isLoggedIn); // 出力:bool(true) - !false は true

// 例2:true を反転
var_dump(!$isAdmin);    // 出力:bool(false) - !true は false

// 例3:比較式の否定($age = 25 の場合、($age > 30) は false)
var_dump(!($age > 30)); // 出力:bool(true) - !false は true
?>

3. 実践的なケーススタディ

比較演算子と論理演算子を組み合わせて、Web開発で頻繁に遭遇するユーザーバリデーションや権限チェックのシナリオを構築してみましょう。

3.1 ユーザー認証チェック

ユーザーがログインを試みるシーンを想定します。入力されたユーザー名とパスワードがデータベース内の情報と完全に一致し、かつアカウントが有効であるかをチェックする必要があります。

<?php
$inputUsername = "admin_user";
$inputPassword = "securePassword123";

$storedUsername = "admin_user";
$storedPassword = "securePassword123";
$isAccountActive = true;

// ユーザー名、パスワードが厳密に一致し、かつアカウントが有効であることをチェック
if (($inputUsername === $storedUsername) && ($inputPassword === $storedPassword) && $isAccountActive) {
    echo "ログイン成功!ようこそ、" . $inputUsername . "さん。\n";
} else {
    echo "ログイン失敗。クレデンシャル(認証情報)またはアカウントステータスを確認してください。\n";
}

// シナリオ 2:パスワードが正しくない場合
$inputPassword2 = "wrongPassword";
if (($inputUsername === $storedUsername) && ($inputPassword2 === $storedPassword) && $isAccountActive) {
    echo "この行はプリントされません。\n";
} else {
    echo "誤ったパスワード ('wrongPassword') によるログイン失敗。\n"; // こちらが出力されます
}
?>

この例では、正確なクレデンシャル比較のために厳密な全等 (===) を使用し、論理積 (&&) によってすべての条件(ユーザー名一致、パスワード一致、アカウント有効)が同時に満たされた場合のみログインを許可しています。

3.2 オンライン注文フォームのバリデーション

オンラインショップの注文フォームを想定します。以下のようなビジネスルールがあるとします:

  1. 購入数量は正の整数であること。
  2. 配送設定は「standard(通常)」または「express(お急ぎ便)」であること。
  3. 「express」を選択した場合、注文合計額が $50 以上であること。
<?php
$quantity = 3;
$deliveryPreference = "express";
$orderTotal = 65.50; // 計算された合計金額

// 条件 1:数量が有効(0より大きく、かつ整数タイプである)
$isValidQuantity = ($quantity > 0 && is_int($quantity)); // is_int() は変数が整数かチェックするビルトイン関数

// 条件 2:配送設定が有効
$isValidDeliveryPreference = ($deliveryPreference === "standard" || $deliveryPreference === "express");

// 条件 3:お急ぎ便を選択した場合の金額チェック
$isExpressEligible = true; // デフォルトで適格とする
if ($deliveryPreference === "express") {
    $isExpressEligible = ($orderTotal >= 50); // 金額が50に満たない場合、false になる
}

// 論理演算子ですべての条件を組み合わせる
if ($isValidQuantity && $isValidDeliveryPreference && $isExpressEligible) {
    echo "注文詳細は有効です。処理を継続します。\n";
} else {
    echo "注文のバリデーションに失敗しました。入力を確認してください。\n";
    if (!$isValidQuantity) {
        echo "- 数量は正の整数でなければなりません。\n";
    }
    if (!$isValidDeliveryPreference) {
        echo "- 無効な配送オプションです。\n";
    }
    if (!$isExpressEligible) {
        echo "- お急ぎ便の利用には $50 以上の注文合計額が必要です。\n";
    }
}
?>

この包括的な例は、比較演算子 (>, ===, >=) と論理演算子 (&&, ||, !) を組み合わせて、複数のビジネスロジックに基づいたユーザー入力の検証をいかに効率的に処理できるかを示しています。