Pregunta

I'm reviewing my intern's code, and I stumbled upon something like this :

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

I thought he made a mistake, confusing & and && (I excepted a logical AND)

But, in fact, his code works as expected, and I can't understand why. In my mind, >= has precedence on ==, which also has precedence on & (reference).

So, I tested (1 == 0 & 1 >= 0) and it output 0. I expected 1, cause in my mind, it was like:

  • 1 >= 0 returns true,
  • Then 1 == 0 gives false,
  • So the expression is now (false & true), which I thought equal to (0 & 1)
  • Which equals 1...
  • So his & is acting like a ||.

Where am I wrong??

¿Fue útil?

Solución

In PHP, a bitwise AND & on two booleans will convert them to integers (i.e. one or zero) and perform the AND. When the result of this operation is evaluated as a boolean, the result actually equates to the same functionality as a logical AND &&.

0 & 1 // 0, false
1 & 0 // 0, false
1 & 1 // 1, true
0 & 0 // 0, false

Proof

The intern will have mistaken the two operators, because there is no good reason to do this - you lose short-circuit evaluation and you add a few unnecessary type casts.

But it does actually work in the same way as a logical AND in this scenario.

In theory, your precedence argument is correct, but it only applies when there's ambiguity:

$foo = $b >= k1;
if ($a == 1 & $foo) $a = 2;

This could produce a different result from the one you intended, and you should write:

$foo = $b >= k1;
if (($a == 1) & $foo) $a = 2;
// or
if ($a == (1 & $foo)) $a = 2;

...depending on what you wanted.

But since you can't do:

$foo = 0 & $b;
if ($a == $foo >= k1) $a = 2;

...the code show can only be interpreted one way so it would be "safe", even if it's not exactly what you intended.

However, there's still very little danger unless you start mixing logical and bitwise operators - precedence-wise, the two types of operator are right next to each other, so something like:

if ($foo & $bar && $baz | $qux) // ...

...is in serious danger of doing something unexpected.

It's also worth noting that actually & is fairly reliable (it should still give the expected result, it's just inefficient and it won't short-circuit) - it's | that might start doing odd things.

However, you would obviously never do this anyway, you would use braces, because this version is quite opaque readability-wise.

Otros consejos

Your mistake is here:

  • So the expression is now (false & true), which I thought equal to (0 & 1)
  • Which equals 1...

0 & 1 actually equals 0.

Boolean algebra is isomorphic to bitwise operators, that's the basis of binary computers.

(0 & 1) is 0

The & operator works the same for logical values true and false as &&, except that it doesn't short-circuit i.e. omit evaluating the second expression when possible.

It's perfectly simple. As you know the bitwise & returns the bits that are "on" in both operands:

0011
0010
----- &
0010

The bitwise | will set all bits that are set in either one (or both) of the operands:

0011
0010
----- |
0011

In your case, true and false are coerced to ints (0 and 1), which yields

0001
0000
----- &
0000

It's That simple

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top