主题
逻辑运算符
逻辑运算符把多个「是 / 否」拼成一个条件,结果仍然是布尔值。if、循环、提前返回都靠它。
php
<?php
$age = 20;
$hasTicket = true;
if ($age >= 18 && $hasTicket) {
echo "可以入场\n";
}
if ($age < 18 || !$hasTicket) {
echo "不能入场\n";
}一览
| 运算符 | 名称 | 为 true 的情况 |
|---|---|---|
&& | 与 | 两边都为真 |
|| | 或 | 至少一边为真 |
! | 非 | 右边为假 |
and | 与 | 同 &&,但优先级更低 |
or | 或 | 同 ||,但优先级更低 |
xor | 异或 | 两边一真一假 |
推荐日常用 &&、||、!。and / or 很容易和赋值搅在一起,见下文。
真和假
逻辑运算会把操作数当成布尔值。下面这些在布尔上下文里是 false,其余一般是 true:
| 值 | 当成 |
|---|---|
false | 假 |
0、0.0 | 假 |
""、"0" | 假 |
[] | 假 |
null | 假 |
其他(包括 "false"、"0.0"、[0]) | 真 |
php
<?php
var_dump((bool) 1); // true
var_dump((bool) 0); // false
var_dump((bool) "0"); // false
var_dump((bool) "false"); // true,非空字符串
var_dump((bool) []); // false
var_dump((bool) [0]); // true,数组里有元素需要精确区分 0、""、null 时,用 ===,不要只靠逻辑运算的真假。比较规则见 比较运算符。
与 &&、或 ||、非 !
php
<?php
$loggedIn = true;
$isAdmin = false;
var_dump($loggedIn && $isAdmin); // false,要两边都真
var_dump($loggedIn || $isAdmin); // true,有一边真就行
var_dump(!$isAdmin); // true,取反真值表(A、B 为布尔值):
| A | B | A && B | A || B | !A |
|---|---|---|---|---|
| true | true | true | true | false |
| true | false | false | true | false |
| false | true | false | true | true |
| false | false | false | false | true |
xor 是「两个里恰好一个为真」:
php
<?php
var_dump(true xor true); // false
var_dump(true xor false); // true实际项目里 xor 很少用,用 !== 往往更直观:$a !== $b(在两边已经是 bool 时)。
短路求值
&& 和 || 不一定会算右边:
$a && $b:$a为假时,整个式子已经是假,$b不会执行$a || $b:$a为真时,整个式子已经是真,$b不会执行
php
<?php
function ping(): bool
{
echo "ping\n";
return true;
}
false && ping(); // 不会输出 ping
true || ping(); // 不会输出 ping
true && ping(); // 输出 ping这很有用:先检查「值在不在」,再使用它,避免 Warning:
php
<?php
$config = ["host" => "localhost"];
if (isset($config["host"]) && $config["host"] !== "") {
echo $config["host"], "\n";
}isset() 为假时不会再读 $config["host"] 去做后面的比较。反过来写就失去这层保护。
and / or 同样短路。xor、! 没有「跳过右边」这回事(! 只有一个操作数)。
&& 和 and 的优先级陷阱
&& / || 的优先级高于赋值;and / or 的优先级低于赋值。于是:
php
<?php
$ok = true && false;
var_dump($ok); // false,先算 true && false,再赋给 $ok
$ok = true and false;
var_dump($ok); // true,实际是 ($ok = true) and false第二行里 false 被算了,但结果没赋给 $ok。这类 bug 很隐蔽。
php
<?php
$found = $user = "xiaoming" or "guest";
// 实际是:($found = ($user = "xiaoming")) or "guest"需要「逻辑结果赋给变量」时:
php
<?php
$ok = true && false; // 推荐
$ok = (true and false); // 用 and 就必须加括号本指南统一用 && / ||。
组合比较条件
逻辑运算经常和比较写在一起:
php
<?php
$age = 22;
$vip = true;
$banned = false;
$canEnter = $age >= 18 && !$banned && ($vip || $age >= 21);
var_dump($canEnter);多层条件时用括号标明意图,或拆成中间变量:
php
<?php
$isAdult = $age >= 18;
$allowed = !$banned;
$canEnter = $isAdult && $allowed && ($vip || $age >= 21);! 的优先级很高,!$a && $b 是 (!$a) && $b,不是 !($a && $b)。
书写建议
- 用
&&/||/!,避开and/or - 利用短路:先
isset/!== null,再读属性 - 不要写
if ($x == true),直接if ($x);要区分类型时用=== true - 否定复杂条件时,宁可
if (!$ready)配一个语义清楚的变量,也不要一长串!套括号 - 多个条件优先拆行或拆变量,不要在一行里链太长
练习
$score = 72、$submitted = true,写出「已提交且分数及格」的条件并var_dump。- 用短路:只有
$name非空时才echo欢迎语(空字符串不输出)。 - 分别运行
$ok = false && true;和$ok = false and true;,解释$ok为什么不同。 - 列出
0、"0"、""、"false"、[]各自(bool)转换结果。