論理演算子(&& || ! / and or not)
複数の条件を組み合わせて判定するには論理演算子を使用します。『PHP』には記号形式(『&&』・『||』・『!』)とアルファベット形式(『and』・『or』・『not』)の2種類があり、演算子の優先度が異なるため使い分けに注意が必要です。
論理演算子一覧
| 演算子 | 別形式 | 名称 | 概要 |
|---|---|---|---|
| && | and | 論理AND | 両辺がともに『true』の場合に『true』を返します。 |
| || | or | 論理OR | どちらか一方でも『true』の場合に『true』を返します。 |
| ! | not | 論理NOT | 真偽値を反転します。『true』は『false』に、『false』は『true』になります。 |
| xor | (なし) | 排他的論理OR | 両辺の真偽値が異なる場合にのみ『true』を返します。 |
&& と and の違い(演算子の優先度)
記号形式(『&&』・『||』・『!』)とアルファベット形式(『and』・『or』・『not』)は同じ論理演算を行いますが、演算子の優先度が異なります。『&&』と『||』は代入演算子(『=』)より高い優先度を持ちますが、『and』と『or』は代入演算子より低い優先度しか持ちません。
| 優先度(高い順) | 演算子 |
|---|---|
| 高い | ! (論理NOT・記号形式) |
| ↑ | && (論理AND・記号形式) |
| ↑ | || (論理OR・記号形式) |
| ↑ | = (代入演算子) |
| ↑ | not (論理NOT・アルファベット形式) |
| ↑ | and (論理AND・アルファベット形式) |
| 低い | or (論理OR・アルファベット形式) |
この優先度の違いにより、代入と組み合わせた式では『and』・『or』を使うと意図しない結果になることがあります。通常のコードでは『&&』と『||』が使われることが多いです。
短絡評価(ショートサーキット評価)
PHPの論理演算子は「短絡評価」を行います。『&&』では左辺が『false』と確定した時点で右辺を評価しません。『||』では左辺が『true』と確定した時点で右辺を評価しません。これは単なる最適化ではなく、コードを簡潔に書くパターンとしても活用されます。
| 演算子 | 短絡評価の条件 | 結果 |
|---|---|---|
| && | 左辺が『false』のとき | 右辺を評価せず、全体の結果は『false』になります。 |
| || | 左辺が『true』のとき | 右辺を評価せず、全体の結果は『true』になります。 |
xor 演算子
『xor』は排他的論理OR(exclusive OR)です。両辺の値が異なる場合のみ『true』を返します。両辺が同じ(両方『true』または両方『false』)場合は『false』になります。
| 左辺 | 右辺 | xor の結果 |
|---|---|---|
| true | true | false(同じなのでfalseです。) |
| true | false | true(異なるのでtrueです。) |
| false | true | true(異なるのでtrueです。) |
| false | false | false(同じなのでfalseです。) |
サンプルコード
logical_basic.php
<?php
// Steins;Gate のキャラクターを使って論理演算子の基本を確認します
$characterName = "岡部倫太郎";
$isLabMember = true; // ラボメンかどうか
$hasDiviner = true; // シュタインズゲートの選択者かどうか
$isEnemy = false; // 敵対勢力かどうか
// &&(AND): 両方trueの場合のみtrueになります
if ($isLabMember && $hasDiviner) {
echo $characterName . ": ラボメンかつ選択者です\n";
}
// ||(OR): 片方でもtrueであればtrueになります
if ($isLabMember || $isEnemy) {
echo $characterName . ": ラボメンまたは敵対勢力に該当します\n";
}
// !(NOT): 真偽値を反転します
if (!$isEnemy) {
echo $characterName . ": 敵対勢力ではありません\n";
}
// 複合条件: &&とも||を組み合わせます。括弧で優先順位を明確にします
$isDanger = ($isEnemy && $hasDiviner) || (!$isLabMember && !$hasDiviner);
var_dump($isDanger); // bool(false)
実行すると次のように出力されます。
php logical_basic.php 岡部倫太郎: ラボメンかつ選択者です 岡部倫太郎: ラボメンまたは敵対勢力に該当します 岡部倫太郎: 敵対勢力ではありません bool(false)
logical_and_or_priority.php
<?php
// &&とandの演算子優先度の違いを確認します
// andはコード代入演算子(=)より優先度が低いため、代入が先に行われます
// &&の場合: 代入より優先度が高いため、まず論理演算を行ってから代入します
$result1 = true && false;
var_dump($result1); // bool(false) — (true && false) の結果をresult1に代入します
// andの場合: 代入より優先度が低いため、まずtrue(右辺)がresult2に代入され
// その後andが評価されます(式全体の評価結果は捨てられます)
$result2 = true and false;
var_dump($result2); // bool(true) — ($result2 = true) and false の順で評価されます
echo "\n";
// 実務で紛らわしい例: 関数の戻り値を変数に受け取りつつ条件判定する場合です
function connectTimeMachine(): bool
{
// タイムマシンへの接続を試みる(ここでは常にfalseを返す想定)
return false;
}
// 推奨: &&を使えば意図通りに動作します
$connected = connectTimeMachine();
if (!$connected) {
echo "接続失敗: &&パターン(正しい)\n";
}
// 注意: and を使った代入は意図しない動作になります
$connected2 = connectTimeMachine() and die("接続失敗"); // dieは呼ばれません
// 上記は ($connected2 = connectTimeMachine()) and die(...) と解釈されます
var_dump($connected2); // bool(false)
実行すると次のように出力されます。
php logical_and_or_priority.php bool(false) bool(true) 接続失敗: &&パターン(正しい) bool(false)
logical_short_circuit.php
<?php
// 短絡評価を利用した初期値設定パターンです
// ||の短絡評価を使い、左辺がfalsy(偽として扱われる値)の場合に右辺をデフォルト値として使います
// ユーザーが入力したキャラクター名(空の場合もある想定)
$inputName = ""; // 空文字はfalsy(偽)として扱われます
// ||の短絡評価: 左辺がfalsyなら右辺が評価されて代入されます
$characterName = $inputName || "鳳凰院凶真";
var_dump($characterName); // bool(true) — ||の結果はboolになるため注意が必要です
echo "\n";
// null合体演算子(??)が推奨される書き方(PHP 7以降)です
$inputName2 = ""; // 空文字
$characterName2 = $inputName2 ?: "鳳凰院凶真"; // ?:(Elvis演算子)はfalsy判定で使えます
echo "Elvis演算子: " . $characterName2 . "\n"; // 鳳凰院凶真
$inputName3 = "岡部倫太郎";
$characterName3 = $inputName3 ?: "鳳凰院凶真"; // 左辺がtruthyなのでそのまま使われます
echo "Elvis演算子: " . $characterName3 . "\n"; // 岡部倫太郎
echo "\n";
// &&の短絡評価: 左辺がfalsyなら右辺は評価されません
$isConnected = false;
// isConnectedがfalseのため、右辺の処理は実行されません(短絡評価)
$isConnected && sendSignal();
echo "短絡評価のため sendSignal() は呼ばれていません\n";
// isConnectedがtrueの場合は右辺が実行されます
$isConnected = true;
$isConnected && print("タイムマシン接続完了\n");
function sendSignal(): void
{
echo "シグナル送信\n"; // この行は短絡評価により呼ばれません
}
実行すると次のように出力されます。
php logical_short_circuit.php bool(true) Elvis演算子: 鳳凰院凶真 Elvis演算子: 岡部倫太郎 短絡評価のため sendSignal() は呼ばれていません タイムマシン接続完了
logical_xor.php
<?php
// xor(排他的論理OR): 両辺の値が異なる場合のみtrueになります
// 世界線の観測者は同時に2人存在できない、という設定で確認します
$kurisu = true; // クリスが世界線の観測者かどうか
$suzuha = false; // 鈴羽が世界線の観測者かどうか
// 片方だけがtrueなのでxorはtrueになります
var_dump($kurisu xor $suzuha); // bool(true)
// 両方trueの場合はxorはfalseになります
$okabe = true;
var_dump($kurisu xor $okabe); // bool(false)
// 両方falseの場合もxorはfalseになります
$moeka = false;
var_dump($suzuha xor $moeka); // bool(false)
echo "\n";
// 実用例: 2つのフラグのうち、必ずどちらか一方だけが有効であることを検証します
$isSteinsGateWorldLine = true; // シュタインズゲートの世界線かどうか
$isBetaWorldLine = false; // β世界線かどうか
if ($isSteinsGateWorldLine xor $isBetaWorldLine) {
echo "世界線は一方のみ有効です\n";
} else {
echo "世界線の状態が矛盾しています\n";
}
実行すると次のように出力されます。
php logical_xor.php bool(true) bool(false) bool(false) 世界線は一方のみ有効です
logical_condition_techniques.php
<?php
// 論理演算子を使った簡潔な条件記述テクニックです
// isset()と&&を組み合わせた安全なアクセス
$labMembers = [
"okabe" => ["name" => "岡部倫太郎", "labMemberNo" => "001"],
"kurisu" => ["name" => "牧瀬紅莉栖", "labMemberNo" => "004"],
];
$key = "kurisu";
// まず配列キーの存在を確認してからアクセスします(短絡評価により安全です)
if (isset($labMembers[$key]) && $labMembers[$key]['labMemberNo'] === "004") {
echo $labMembers[$key]['name'] . ": ラボメンNo.004です\n";
}
// 存在しないキーでも短絡評価により右辺が評価されないためエラーになりません
$unknownKey = "moeka";
if (isset($labMembers[$unknownKey]) && $labMembers[$unknownKey]['labMemberNo'] === "008") {
echo "moeka: ラボメンNo.008です\n"; // 実行されません
} else {
echo "moeka: ラボメンのデータが見つかりません\n";
}
echo "\n";
// null合体演算子(??)と組み合わせたデフォルト値設定
$inputMember = null; // ユーザー入力がnullの場合
// ??はnullまたは未定義のときにデフォルト値を返します
$memberName = $inputMember ?? "ゲスト";
echo "ようこそ、" . $memberName . "さん\n"; // ゲスト
// !!(二重否定)で任意の値を明示的にboolに変換するテクニックです
$divergenceRate = 1.048596; // 世界線変動率
$isReached = !!$divergenceRate; // 0.0以外はtrueに変換されます
var_dump($isReached); // bool(true)
$zeroDivergence = 0.0;
var_dump(!!$zeroDivergence); // bool(false)
実行すると次のように出力されます。
php logical_condition_techniques.php 牧瀬紅莉栖: ラボメンNo.004です moeka: ラボメンのデータが見つかりません ようこそ、ゲストさん bool(true) bool(false)
よくあるミス
よくあるミス1: &&とandの優先度の違いで代入が意図通りにならない
『and』は代入演算子(『=』)より優先度が低いため、『$result = 値1 and 値2』と書くと、まず代入が行われてから『and』が評価されます。変数には値1が代入されてしまい、論理演算の結果(値1 and 値2)は変数に入りません。
ng_priority.php
<?php // andの優先度が低いため、代入が先に行われます $isMember = true; $isActive = false; // 意図: (true and false) をresultに代入したい $result = $isMember and $isActive; // 実際の解釈: ($result = $isMember) and $isActive // resultにはtrueが入ってしまいます var_dump($result); // bool(true) — 意図した結果ではありません
実行すると次のように出力されます。
php ng_priority.php bool(true)
ok_priority.php
<?php // &&を使えば代入より優先度が高いため意図通りに動作します $isMember = true; $isActive = false; $result = $isMember && $isActive; // 解釈: $result = (true && false) var_dump($result); // bool(false) — 正しい結果です
実行すると次のように出力されます。
php ok_priority.php bool(false)
よくあるミス2: !演算子の優先度で意図しない結果になる
『!』は優先度が高いため、複合条件に使う場合は括弧が必要です。括弧がないと『!』が最初のオペランドだけに適用されてしまいます。
ng_not.php
<?php $isLabMember = false; $hasDiviner = true; // 意図: !(isLabMember && hasDiviner) を評価したい // 実際: (!isLabMember) && hasDiviner と解釈されます $result = !$isLabMember && $hasDiviner; var_dump($result); // bool(true) — 意図した結果と異なる場合があります // 意図した式: !(false && true) = !false = true(この場合は偶然一致) // 別の値で試すと違いが明確になります $a = true; $b = true; var_dump(!$a && $b); // bool(false) — (!true) && true = false && true = false var_dump(!($a && $b)); // bool(false) — !(true && true) = !true = false(この例では同じ) $c = false; $d = false; var_dump(!$c && $d); // bool(false) — (!false) && false = true && false = false var_dump(!($c && $d)); // bool(true) — !(false && false) = !false = true(異なる結果)
実行すると次のように出力されます。
php ng_not.php bool(true) bool(false) bool(false) bool(false) bool(false) bool(true)
ok_not.php
<?php $c = false; $d = false; // 複合条件全体を否定したい場合は括弧で囲みます $result = !($c && $d); // !(false && false) = !false = true var_dump($result); // bool(true)
実行すると次のように出力されます。
php ok_not.php bool(true)
よくあるミス3: 短絡評価で関数が呼ばれないケース
『&&』や『||』の短絡評価によって、右辺の関数が呼ばれない場合があります。関数呼び出しを条件として使うコードでは、短絡評価により関数が実行されないことを把握しておく必要があります。
ng_short_circuit.php
<?php
function saveData(): bool
{
echo "データを保存しました\n";
return true;
}
$isConnected = false;
// isConnectedがfalseのため、saveData()は呼ばれません(短絡評価)
// 保存処理が実行されることを期待していると問題になります
$isConnected && saveData();
echo "処理を終了します\n";
実行すると次のように出力されます。
php ng_short_circuit.php 処理を終了します
ok_short_circuit.php
<?php
function saveData(): bool
{
echo "データを保存しました\n";
return true;
}
$isConnected = false;
// 副作用のある処理は明示的にif文で書くほうが意図が明確です
if ($isConnected) {
saveData();
}
echo "処理を終了します\n";
実行すると次のように出力されます。
php ok_short_circuit.php 処理を終了します
概要
論理演算子には記号形式(『&&』・『||』・『!』)とアルファベット形式(『and』・『or』・『not』)の2種類があります。両者は見た目は似ていますが演算子の優先度が大きく異なり、特に代入と組み合わせた場合に意図しない挙動を生じることがあります。原則として記号形式の『&&』と『||』を使用し、アルファベット形式は避けるのが安全です。
『&&』と『||』は短絡評価(ショートサーキット評価)を行います。『&&』は左辺が『false』の時点で右辺を評価せず、『||』は左辺が『true』の時点で右辺を評価しません。これを利用して、変数の存在確認を先に行ってから値にアクセスする安全なパターンや、初期値設定に使う『?:』(Elvis演算子)・『??』(null合体演算子)のパターンが広く使われています。null合体演算子については『isset() / empty()』も参照してください。
『xor』演算子は両辺の真偽値が異なる場合のみ『true』を返します。排他的な状態(どちらか一方だけが有効であることの検証)に使用します。条件分岐の詳細は『if / elseif / else』を、値の比較については『比較演算子』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。