12.

PHP 条件分岐完全ガイド (if/switch/match)

編集
この記事の要点
  • PHP の条件分岐は if/elseif/else, switch, match (PHP 8+), 三項演算子, Null合体 の 5 種
  • switch は 緩い比較 (==) → 型まで見たいなら match を使う
  • 三項は短い式向き、ネストすると可読性が一気に落ちる → match や Early Return に逃がす
  • ネストが深くなったら Early Return (Guard Clause) でフラット化
  • 複雑な if-elseif 連鎖は Strategy パターン連想配列の dispatch に置換

if / elseif / else

if ($age >= 20) {
    echo 'adult';
} elseif ($age >= 13) {
    echo 'teen';
} else {
    echo 'child';
}

// 中括弧省略は推奨しない (バグの温床)
if ($x > 0) echo 'pos';   // 動くが避ける

// テンプレート (Blade ではなく素 PHP)
?>
<?php if ($user->isAdmin()): ?>
    <a href="/admin">Admin</a>
<?php elseif ($user->isLoggedIn()): ?>
    <a href="/mypage">My Page</a>
<?php else: ?>
    <a href="/login">Login</a>
<?php endif; ?>
<?php

switch

switch ($status) {
    case 'pending':
    case 'processing':           // fall-through で OR
        echo '進行中';
        break;
    case 'shipped':
        echo '発送済';
        break;
    case 'delivered':
        echo '配達完了';
        break;
    default:
        echo '不明';
}

// ★ 罠1: 緩い比較 (==)
switch ($x) {
    case 0:    echo 'zero'; break;
    case '0':  echo 'str';  break;   // 到達しない (0 == '0')
}

// ★ 罠2: break 忘れ
switch ($x) {
    case 1:
        $y = 'one';
        // break 忘れ → 2 のブロックも実行されてしまう
    case 2:
        $y = 'two';
        break;
}

match 式 (PHP 8+)

// 戻り値を持つ「式」
$label = match ($status) {
    1, 2 => '進行中',           // OR
    3    => '発送済',
    4    => '配達完了',
    default => '不明',
};

// 厳密比較 (===)
$x = match (0) {
    '0' => 'str',
    0   => 'int',     // ← ここに当たる
};

// 該当なし (default なし) → UnhandledMatchError
try {
    $r = match (99) {
        1 => 'a',
        2 => 'b',
    };
} catch (\UnhandledMatchError $e) {
    // 全パターン網羅漏れを実行時に検出できる
}

// 真偽条件のディスパッチ
$cat = match (true) {
    $age < 13 => 'child',
    $age < 20 => 'teen',
    default   => 'adult',
};

switch vs match 比較表

項目switchmatch (PHP 8+)
比較== (緩い)=== (厳密)
break必要 (忘れバグ)不要
戻り値なし (文)あり (式)
網羅性抜け落ち放置UnhandledMatchError
複文OK1 式のみ (匿名関数で回避可)
fall-throughありなし (OR は 1, 2 =>)

三項演算子

$label = $age >= 20 ? 'adult' : 'minor';

// Elvis (PHP 5.3+)
$name = $input ?: 'Guest';

// Null 合体
$name = $input ?? 'Guest';

// ❌ ネスト三項は禁止 (PHP 8+ は括弧必須)
$cat = $age < 13 ? 'child' : ($age < 20 ? 'teen' : 'adult');
// → match の方が読みやすい
$cat = match (true) {
    $age < 13 => 'child',
    $age < 20 => 'teen',
    default   => 'adult',
};

Early Return でネストを潰す

// ❌ ネスト地獄
function process(?User $user): string {
    if ($user !== null) {
        if ($user->isActive()) {
            if ($user->hasPermission('edit')) {
                return doEdit($user);
            } else {
                return 'no permission';
            }
        } else {
            return 'inactive';
        }
    } else {
        return 'no user';
    }
}

// ✅ Early Return でフラット
function process(?User $user): string {
    if ($user === null)              return 'no user';
    if (!$user->isActive())          return 'inactive';
    if (!$user->hasPermission('edit')) return 'no permission';
    return doEdit($user);
}

Strategy パターンで if 連鎖を消す

// ❌ どんどん増える if-elseif
function calcShipping(string $method, float $weight): int {
    if ($method === 'yamato') {
        return $weight * 100 + 500;
    } elseif ($method === 'sagawa') {
        return $weight * 90 + 600;
    } elseif ($method === 'japan_post') {
        return $weight * 80 + 400;
    }
    throw new InvalidArgumentException();
}

// ✅ 連想配列ディスパッチ
$strategies = [
    'yamato'     => fn($w) => $w * 100 + 500,
    'sagawa'     => fn($w) => $w * 90  + 600,
    'japan_post' => fn($w) => $w * 80  + 400,
];

function calcShipping(string $m, float $w) use ($strategies): int {
    $fn = $strategies[$m] ?? throw new InvalidArgumentException();
    return $fn($w);
}

isset / empty / null 合体の使い分け

// 入力値の有無
if (isset($_POST['name'])) { /* 設定済 (null以外) */ }
if (!empty($_POST['name'])) { /* truthy */ }   // ⚠ 0 / "0" / "" も false
$name = $_POST['name'] ?? '';                  // null → ''

// PHP 7+: 短く書ける
$user = User::find($id) ?? throw new NotFoundException();   // PHP 8+

FAQ

Q: if と switch、どちらを使うべき?
A: 同じ変数を多数の値と比較するなら switch / match、複数条件を組合せるなら if。PHP 8 以降は match を第一候補に。

Q: elseifelse if の違い
A: ほぼ同じだが、テンプレート構文 (endif) では elseif でないと動かない。常に elseif 推奨。

Q: ネストした条件分岐をリファクタしたい
A: 順に Early Return → 連想配列ディスパッチ → Strategy パターン → State パターン と検討。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本事項
  2. HTMLへの埋め込み
  3. 変数
  4. 可変変数
  5. 定数
  6. データ型
  7. キャスト
  8. エスケープ文字
  9. 配列
  10. 演算子
  11. 代入の際の注意点
  12. 条件分岐
  13. 繰り返し処理
  14. クラスとインスタンス
  15. コンストラクタ
  16. 関数
  17. スーパーグローバル変数
  18. スコープ
  19. staticについて
  20. yieldについて
  21. ファイルのアップロード方法
  22. DB接続方法
  23. SQL実行方法
  24. カプセル化の具体例
  25. 継承の構文
  26. オーバーライド
  27. ポリモーフィズム(多様性)の具体例
  28. 抽象クラス・メソッドの構文と具体例
  29. GET通信
  30. try catchで全てのエラーを拾う方法

最近更新/作成されたページ