我正在审查实习生的代码,我偶然发现了这样的东西:
//k* are defined constants
if ($a == 0 & $b >= k0) $a = 1;
if ($a == 1 & $b >= k1) $a = 2;
if ($a == 2 & $b >= k2) $a = 3;
我认为他犯了一个错误,混淆了&
和&&
(我除了一个合乎逻辑的 AND(
但是,事实上,他的代码按预期工作,我不明白为什么。在我看来,>=
优先于==
,&
(参考(也有优先权。
所以,我测试了(1 == 0 & 1 >= 0)
,它输出0
.我期待1
,因为在我心中,它就像:
-
1 >= 0
返回true
, - 然后
1 == 0
给出false
, - 所以表达式现在是
(false & true)
,我认为等于(0 & 1)
- 这等于
1
... - 所以他的
&
表现得像个||
.
我错在哪里??
在 PHP 中,两个布尔值上的按位 AND &
会将它们转换为整数(即 1 或 0(并执行 AND。当此操作的结果被评估为布尔值时,结果实际上等同于与逻辑 AND &&
相同的功能。
0 & 1 // 0, false
1 & 0 // 0, false
1 & 1 // 1, true
0 & 0 // 0, false
证明
实习生会误会两个运算符,因为没有充分的理由这样做 - 你失去了短路评估,你添加了一些不必要的类型转换。
但在这种情况下,它实际上以与逻辑 AND 相同的方式工作。
从理论上讲,您的优先参数是正确的,但它仅适用于存在歧义的情况:
$foo = $b >= k1;
if ($a == 1 & $foo) $a = 2;
这可能会产生与预期不同的结果,您应该编写:
$foo = $b >= k1;
if (($a == 1) & $foo) $a = 2;
// or
if ($a == (1 & $foo)) $a = 2;
。取决于你想要什么。
但是既然你不能做:
$foo = 0 & $b;
if ($a == $foo >= k1) $a = 2;
。代码显示只能以一种方式解释,因此它是"安全的",即使它不完全是你想要的。
但是,除非您开始混合逻辑运算符和按位运算符,否则危险仍然很小 - 优先级方面,两种类型的运算符彼此相邻,因此如下所示:
if ($foo & $bar && $baz | $qux) // ...
。有做一些意想不到的事情的严重危险。
还值得注意的是,实际上&
是相当可靠的(它仍然应该给出预期的结果,它只是效率低下,不会短路( - |
可能会开始做奇怪的事情。
但是,您显然永远不会这样做,您会使用大括号,因为此版本在可读性方面非常不透明。
你的错误在这里:
- 所以表达式现在是(假和真(,我认为等于(0和1(
- 这等于 1...
0 & 1
实际上等于0
.
布尔代数与按位运算符同构,这是二进制计算机的基础。
(0 & 1)
0
&运算符对于逻辑值 true 和 false 的工作方式与 && 相同,只是它不会短路,即尽可能省略计算第二个表达式。
这非常简单。如您所知,按位&
返回两个操作数中">on">的位:
0011
0010
----- &
0010
按位|
将设置在一个(或两个(操作数中设置的所有位:
0011
0010
----- |
0011
在您的情况下,true
和 false
被强制转换为整数(0 和 1(,这会产生
0001
0000
----- &
0000
就是这么简单