2

The following code understandably yields "dev" when $_SERVER['MODE'] is not set:

$_SERVER['MODE'] ?? null === 'production' ? 'prod' : 'dev'

That is because $_SERVER['MODE'] ?? null resolves to NULL which, of course, is not strictly equal to "production", so the right operand of the ternary expression prevails.

However, if I set $_SERVER['MODE'] to just any truthy value, things become strange. The code yields "prod"!

I do not understand why. When $_SERVER['MODE'] is set, the null coalescing resolves to whatever value it is set to. So, unless it is set to "production", the right operand of the ternary expression should still prevail. Why does it not?

Besides, if I add brackets like this:

($_SERVER['MODE'] ?? null) === 'production' ? 'prod' : 'dev'

— then it works as expected. But why not without the brackets?

Related but not dupe: PHP null coalesce + ternary operators strange behavior

P.S. This confusion just costed me $40. $_SERVER['MODE'] was set to "dev" but, as the expression resolved to "prod", real AWS instances were started :D.

4
  • it's because without the brackets, it treats everything to the right of the nullish coalescing operator as a member. It's just like doing ( 3 + 3 ) * 3 = 18 vs 3 + 3 * 3 = 12 Commented Jun 16, 2023 at 1:28
  • @CornelRaiu Even then, "everything to the right of the nullish coalescing operator" should resolve to "dev" shouldn't it? And so, should the whole expression. Commented Jun 16, 2023 at 1:32
  • I don't know why my comment disappeared. Here it is again: stackoverflow.com/questions/67575170/… - even if it's for JS, the same principles apply since the nullish coalescing has higher operator precedence in PHP as well: php.net/manual/en/language.operators.precedence.php Commented Jun 16, 2023 at 1:35
  • @CornelRaiu I am aware of the principles and my application of them concludes that "dev" should be the result. The question is where is the error in my application of the principles, not what the principles are. Commented Jun 16, 2023 at 1:37

1 Answer 1

2

You can test the result of $_SERVER['MODE'] ?? null === 'production' pretty easily by isolating it.

var_dump(1 ?? null === 'production'); // 1

var_dump(null ?? null === 'production'); // false

var_dump(null ?? 'production' === 'production'); // true

That means, your operands are grouped like this unless you add the brackets:

( $_SERVER['MODE'] ?? (null === 'production') ) ? 'prod' : 'dev'

If $_SERVER['MODE'] is any other value than null or false, the resulting operation will be:

$_SERVER['MODE'] ? 'prod' : 'dev'

So, every truthy value will evaluate to 'prod'.

This is because the nullish coalesching operator has a higher precedence order than the ternary operator ( as can be seen here )

I hope that makes sense.

As a piece of advice, try to always add brackets in cases like this. The code is easier to read, maintain, and debug. And no one will go insane or lose money over issues like this one.

Sign up to request clarification or add additional context in comments.

1 Comment

Looks like what I didn't realize was that the strict comparison operator (null === 'production') has even higher precedence than the nullish coalesching. I assumed that ($_SERVER['MODE'] ?? null) will be grouped first and foremost. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.