Why does the PHP null-coalescing operator (??) behave irrationally with == and ===?

125 Views Asked by At
var_dump(3 ?? null);
var_dump(3 ?? null === null);
var_dump(3 === null);
var_dump(3 ?? 1 > 2);
var_dump(null ?? 1 > 2);

What do you consider the outputs to be?

3 # Expected
true # Unexpected: I'd expect false
false # This is also what I'd expect
3 # Wait, what?! Why is it 3 and not true??
false # Oh so it only evaluates the right-side boolean if the left side is null??? How unexpected!

So the question is really this:

Why does the PHP engine value === as higher than ??? In what world would anyone want to compare it like if ($count ?? (null === null)) when that is so counter-intuitive to the desired if (($count ?? null) === null)?

Given $count = 3; if ($count ?? 1 > 2), as a rational person, I would expect this to evaluate to if ((3 ?? 1) > 2) -> if (3 > 2) and return true. Instead, it evaluates to if (3 ?? (1 > 2) -> if (3), which just happens to be truthy. But I don't think anyone would rationally want this evaluation...

It seems like a bug in the interpreter to me. Is there any good reason for this state of affairs?

1

There are 1 best solutions below

0
Nick On BEST ANSWER

You are seeing this result because ?? has lower precedence than any of the comparison operators (see the manual). Thus for example,

$count ?? null === null

evaluates as

$count ?? (null === null)

which evaluates to

$count

as $count is set.

For most of your tests, that then evaluates to 3 or a, which are both truthy, and so the condition test is true. Note that for this particular test, even if $count was unset, it would still evaluate true as null === null. So:

$count = 3;
if ($count ?? null === null) { echo "Noooo!!!\n"; } else { echo "Yes!!\n"; }

will output:

Noooo!!!

The one exception is where $count is set to false, where the result of the evaluation is then false, which gives you your expected result for

if ($count ?? true === true) { echo "Noooo!!!!\n"; } else { echo "Yes!!\n"; }

If you add parentheses to properly specify your desired operation, everything works as expected e.g.

$count = 3;
if (($count ?? null) === null) { echo "Noooo!!!\n"; } else { echo "Yes!!\n"; }

Output:

Yes!!

Demo showing faulty and corrected code for each example on 3v4l.org