タイトル: 条件分岐
SEOタイトル: PHP 条件分岐完全ガイド (if/switch/match)
| この記事の要点 |
|
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 比較表
| 項目 | switch | match (PHP 8+) |
|---|---|---|
| 比較 | == (緩い) | === (厳密) |
| break | 必要 (忘れバグ) | 不要 |
| 戻り値 | なし (文) | あり (式) |
| 網羅性 | 抜け落ち放置 | UnhandledMatchError |
| 複文 | OK | 1 式のみ (匿名関数で回避可) |
| 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: elseif と else if の違い
A: ほぼ同じだが、テンプレート構文 (endif) では elseif でないと動かない。常に elseif 推奨。
Q: ネストした条件分岐をリファクタしたい
A: 順に Early Return → 連想配列ディスパッチ → Strategy パターン → State パターン と検討。