Php 比较优先级混淆


Php comparison precedence confusion

我正在审查实习生的代码,我偶然发现了这样的东西:

//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

在您的情况下,truefalse 被强制转换为整数(0 和 1(,这会产生

0001
0000
----- &
0000

就是这么简单