phpoperator-precedenceassociativity

Unexpected behaviour of "!print("1") || 1" in php


Example1:

if(!print("1") || 1){
   echo "a";
}else{
   echo "b";
}

Output

1b

The Example 1 is printing "1b" instead of "1a". According to me, inside if the final condition should be if(0 || 1) after solving !print("1").

But the Example 2 is printing "1a".

Example 2:

if((!print("1")) || 1){
   echo "a";
}else{
   echo "b";
}

Output

1a

Can you elaborate, why the or condition in the first statement didn't work.


Solution

  • The key thing here is to realise that print is not a function, and doesn't take arguments in parentheses - the parentheses aren't optional, they're just not part of the syntax at all.

    When you write print("1"); the print statement has a single argument, the expression ("1"). That is if course just another way of writing "1" - you could add any number of parentheses and it wouldn't change the value.

    So when you write print("1") || 1 the argument to print is the expression ("1") || 1. That expression is evaluated using PHP's type juggling rules as true || true which is true. Then it's passed to print and - completely coincidentally to what you were trying to print - is type juggled to the string "1".

    The print statement is then treated as an expression returning true, and the ! makes it false, so the if statement doesn't run.

    This is a good reason not to use parentheses next to keywords like print, require, and include - they give the mistaken impression of "attaching" an argument to the keyword.