views:

226

answers:

7

Often in PHP, I see:

$result = mysql_query($query) or die();

Coming from python, I know why this should work, because or returns the first value if it is true in a boolean context, and the second value otherwise (see this).

But when I try the above technique in PHP in another context, for example something like:

$name = "John Doe";
echo $name or "Anonymous";

The or doesn't return the first value ("John Doe"), it returns 1.

Why does this work in the mysql_query() result case, but not in other cases? Is it bad to use in a mysql_query() case (ignore the fact that I am not returning a useful error to the user)?

A: 

That is because echo is not a function, it's a language construct. It mimicks to be a function, but it really isn't :)

I would never use die() like this, it's kind of rough. You should handle your errors appropriately, don't just bail out.

Dennis Haarbrink
I said "ignore the fact that I am not returning a useful error to the user" - that's not part of the question. You've missed the whole problem with this answer. It doesn't matter weather echo is a function or not. `echo (false or true);` or `printf(false or true);` should be the same as `$a = (false or true); echo $a;`
rjmunro
@rjmunro: The first paragraph (tries to) answer your question. What should `echo $name or "John Doe";` do? `(echo $name) or "John Doe"` OR `echo ($name or "John Doe")` ? That is an important matter. And therefore it is important whether it is a function (with a return value) or a language construct (with no return value).
Dennis Haarbrink
+25  A: 

In PHP, variable assignment (the equals sign) and functions both take precedence over the or operator. That means a function gets executed first, then the return value of the function is used in the or comparison. In turn when you use two values/variables together with an or operator, it compares the two values first then returns a Boolean value.

Therefore, the order of evaluation in this example is:

$result = mysql_query($query) or die();
  1. mysql_query($query)
    Returns either a result set for DQL queries such as SELECT, or a Boolean value for DDL, DML or DCL queries such as CREATE, DROP, INSERT, UPDATE, DELETE and ALTER.

  2. $result = mysql_query($query)
    The result of this query execution is assigned to the variable $result.

  3. $result /* = ... */ or die();
    If it's either a result set or true, it's considered true (aka "truthy") so the or condition is satisfied and the statement ends here. Otherwise the script would die() instead.


echo is a language construct and therefore doesn't actually return a value, so it doesn't run like a function before the or comparison is made.

As $name or "Anonymous" is always true because the string "Anonymous" is non-empty and therefore truthy, the echo implicitly converts true to 1, hence that output.

The order of evaluation in this example is:

$name = "John Doe";
echo $name or "Anonymous";
  1. $name = "John Doe";
    Pretty straightforward — assigns the string John Doe to $name.

  2. $name or "Anonymous"
    PHP discovers that $name contains the string John Doe, so what ends up being evaluated is the following:

  3. "John Doe" or "Anonymous"
    Since at least one string is non-empty here, it's considered truthy and the condition is satisfied. This evaluation then returns true.

  4. echo true /* $name or... */;
    Converts true to 1 and prints the number 1.

BoltClock
+1 Great explanation.
karim79
+1 great word, "truthy"
Vinko Vrsalovic
Then I guess this will work with the print-functions like `printf`, or is this the same issue, becaus it produces output? It's a function so it should work, right?
faileN
So `=` is a function but `or` is an operator? I would have thought `=` was also an operator. Also, this is wrong. The `die()` function is not executed before the `or`.
rjmunro
@faileN: that's correct. `printf()` is a function that returns the number of bytes that were printed, so it'll run similarly to the `mysql_query()` call.
BoltClock
@rjmunro: `=` is the assignment operator. It's not a function, but in PHP it *also* takes precedence over the `or` operator. I just clarified in my edit.
BoltClock
+1  A: 

Why should or return anything? or is a normal boolean operator. $a or $b is true if either $a or $b evaluates to true and false otherwise.

The difference between || and or is, that or has a lower operator precedance, even lower than =. This is why

$result = mysql_query($query) or die();

is same as

($result = mysql_query($query)) or (die());

whereas

$result = mysql_query($query) || die();

is same as

$result = (mysql_query($query) || die());

In your case

echo $name or "Anonymous";

gets

(echo $name) or ("Anonymous");

What you are looking for probably is the ternary operator:

echo $name ?: 'Anonymous';

The above will work as of PHP 5.3, if you have only PHP 5.2 use:

echo $name ? $name : 'Anonymous';
nikic
+1  A: 

PHP does something often called "type juggling". In other words: PHP transforms the type of any value for the current use case. Since Strings will be transformed to "true" values, your expression returns true. But echo wants to print an string expression and transforms "true" to 1. Kinda annoying in some cases, but if you know it, you also know how to handle ;)

Check this out, by the way: http://php.net/manual/en/types.comparisons.php

unset
+1  A: 

the or clause is evaluated first and returns a boolean which the echo outputs. If you want to output text you need a if/else construct like:

echo ($name ? $name : 'Anonymous');
dnagirl
or if you're running PHP 5.3+, `echo $name ?: "Anonymous";`
nickf
+1  A: 

The reason actually occurred to me shortly after asking the question. It's about operator precedence. The = happens before the or, so:

$result = mysql_query($query) or die();

is equivalent to:

($result = mysql_query($query)) or die();

not:

$result = (mysql_query($query) or die());

as it would be in Python. So this:

$a = false or true;

will set $a to false, not true, which is bound to catch me out at some point in the future.

rjmunro
A: 

If you wanted to replicate that behavior AND output to the screen/browser, you need a function that will return something other than TRUE. printf() can do that for you.

echo microtime."<br>";
$str = "";
printf("%s",$str) or die();
echo "<br>".microtime();

If $str is empty, null, or false the die() will be called, otherwise, the script will finish executing.

Grant Harkus