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
,1 == 0
gives false
, (false & true)
, which I thought equal to (0 & 1)
1
...&
is acting like a ||
.Where am I wrong??
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
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.