0

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

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

我认为他犯了一个错误,令人困惑&并且&&(我排除了一个逻辑与)

但是,事实上,他的代码按预期工作,我不明白为什么。在我看来,>=优先于==,也优先于&参考)。

所以,我测试(1 == 0 & 1 >= 0)并输出0。我期待1,因为在我看来,就像:

  • 1 >= 0返回true,
  • 然后1 == 0给出false,
  • 所以现在的表达式是(false & true),我认为等于(0 & 1)
  • 这等于1...
  • 所以他&的行为就像一个||

我哪里错了??

4

4 回答 4

3

在 PHP 中,&对两个布尔值进行按位与运算会将它们转换为整数(即​​一或零)并执行与运算。当此操作的结果被评估为布尔值时,结果实际上等同于与逻辑 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) // ...

...有做一些意想不到的事情的严重危险。

还值得注意的是,它实际上&是相当可靠的(它仍然应该给出预期的结果,它只是效率低下并且不会短路)——它|可能会开始做一些奇怪的事情。

然而,你显然永远不会这样做,你会使用大括号,因为这个版本在可读性方面非常不透明。

于 2013-09-02T12:25:29.250 回答
1

这非常简单。如您所知,按位&返回两个操作数中“打开”的位:

0011
0010
----- &
0010

按位|将设置在一个(或两个)操作数中设置的所有位:

0011
0010
----- |
0011

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

0001
0000
----- &
0000

就这么简单

于 2013-09-02T12:34:38.983 回答
1

你的错误在这里:

  • 所以现在的表达式是 (false & true),我认为它等于 (0 & 1)
  • 等于 1...

0 & 1实际上等于0

布尔代数与位运算符同构,这是二进制计算机的基础。

于 2013-09-02T12:26:35.070 回答
1

(0 & 1)0

& 运算符对逻辑值 true 和 false 的工作方式与 && 相同,只是它不会短路,即尽可能省略对第二个表达式的求值。

于 2013-09-02T12:26:41.157 回答