does the condition after && always get evaluated - php

I have this if statement that tests for the 2 conditions below. The second one is a function goodToGo() so I want to call it unless the first condition is already true
$value = 2239;
if ($value < 2000 && goodToGo($value)){
//do stuff
}
function goodToGo($value){
$ret = //some processing of the value
return $ret;
}
My question is about the 2 if conditions $value < 2000 && goodToGo($value). Do they both get evaluated or does the second one only get evaluated when the first one is true?
In other words, are the following 2 blocks the same?
if($value < 2000 && goodToGo($value)) {
//stuff to do
}
if($value < 2000) {
if (goodToGo($value)){
//stuff to do
}
}

No--the second condition won't always be executed (which makes your examples equivalent).
PHP's &&, ||, and, and or operators are implemented as "short-circuit" operators. As soon as a condition is found that forces the result for the overall conditional, evaluation of subsequent conditions stops.
From http://www.php.net/manual/en/language.operators.logical.php
// --------------------
// foo() will never get called as those operators are short-circuit
$a = (false && foo());
$b = (true || foo());
$c = (false and foo());
$d = (true or foo());

Yes. The two blocks are the same. PHP, like most (but not all) languages, uses short-circuit evaluation for && and ||.

The two blocks ARE same.
PHP logical operators are "lazy", they are evaluated only if they are needed.
The following code prints "Hello, world!":
<?php
$a = 10;
isset($a) || die ("variable \$a does not exist.");
print "Hello, world!"
?>
Other logical operators includes &&, and, or.
<?php
perform_action() or die ('failed to perform the action');
?>
is a popular idiom.

the second condition will only be checked if and only if first one is true, hence both statements are equivalent.

Yes, the 2 code blocks you gave are equivalent. PHP has short-circuiting, so when you use
|| and &&, any statement after the first only gets evaluated when necessary.

Always corelate your technical Language with your own language, Likewise here, If I say you in verbal conversation, its just like :You are asking= "if I am hungry '&&' I am eating Pizza" is similar to "If I am hungry then only i am eating Pizza"?
So here you can see that later phrase says that untill i am not hungry i am not eating pizza, and the former says I am humgry and I am eating pizza.
:-)

Related

PHP precedence for && and parentheses

According to the manual:
Parentheses may be used to force precedence, if necessary.
However, it seems && remains higher:
$var = null;
var_dump($var && ($var->a() || $var->b()) && $var->c());
I expect ($var->a() || $var->b()) to be evaluated first, due to the brackets, and throw an error for the missing method. However, the result is bool(false) with no error. How so?
From the official PHP documentation:
// foo() will never get called as those operators are short-circuit
$a = (false && foo());
$b = (true || foo());
$c = (false and foo());
$d = (true or foo());
See short-circuit evaluation.
Basics
Not the full statements gets checked
function A (){ echo "ran A\n"; return false;}
function B (){ echo "ran B\n"; return true;}
if( A && B ){
echo 'Both true';
} else{
echo 'One or both false';
}
Both must be true, but A isn't true, why bother checking the rest? No matter what B returns, the statement will never be true and it will be the else{} (and get 'ran A' and NOT get 'ran B').
Parenthesis
Also, precendence gets prioritized with brackets, but it still goes from left to right:
if( A && (B or C) && D)
A will run. If it's false, no point in continueing. B/C/D dont run
If A=true B will run.
If B=true C wont run, as only one true is needed. Then D is run
If B=false C will run
if C=true D is run
if C=false (and B also is) the inners of the parenthesis are 2xfalse -> false. D wont run as it wont matter
When you understand this concept, you can use this trick to your benefit. An example with the ?? operator:
$thing = $user->getThing() ?? $user->makeNewThing();
You try to get $thing from the user object. If it exists you get it and makeNewThing() never gets called (as it would be useless, to optimized away). If ity doesnt, only then it gets ran.

PHP || and && logical optimization

I'm a bit of an optimization freak (at least by my definition) and this question has been bugging me for quite a while.
I'm wondering if PHP does some optimization on && and ||:
Take the following example:
$a = "apple";
$b = "orange";
if ($a == "orange" && $b == "orange") {
//do stuff
}
When that code executes, it will check if $a is equal to "orange." In this case it isn't. However, there is an && operator. Since the first part ($a == "orange") already returned false, will PHP still check if $b is equal to "orange?"
I have the same question for ||:
$a = "orange";
$b = "orange";
if ($a == "orange" || $b == "orange") {
//do stuff
}
When it checks if $a is equal to "orange," it returns true. Since that would make the || operator return true, will PHP even check the second part of the || (since we already know it will be true)?
Hopefully I am making sense here, and hopefully somebody has an answer for me. Thank you!
PHP uses short circuit evaluation with binary conditionals (such as &&, || or their constant equivalents), so if the result of evaluating the LHS means the RHS isn't necessary, it won't.
For example...
method_exists($obj, 'func') AND $obj->func();
...is an exploitation of this fact. The RHS will only be evaluated if the LHS returns a truthy value in this example. The logic makes sense here, as you only want to call a method if it exists (so long as you're not using __call(), but that's another story).
You can also use OR in a similar fashion.
defined('BASE_PATH') OR die('Restricted access to this file.');
This pattern is used often as the first line in PHP files which are meant to be included and not accessed directly. If the BASE_PATH constant does not exist, the LHS is falsy so it executes the RHS, which die()s the script.
Yes, PHP short-circuits the && and || operators, meaning that no, the right operand won't be evaluated if the value of the left operand means that it doesn't need to be evaluated. There's no need to optimize them. You can test it like this:
function one() {
echo "One";
return false;
}
function two() {
echo "Two";
return true;
}
one() && two(); // Outputs One
echo "\n";
two() || one(); // Outputs Two
Here's a demo. If there were no short-circuiting, you'd get:
OneTwo
TwoOne

Does PHP have short-circuit evaluation?

Given the following code:
if (is_valid($string) && up_to_length($string) && file_exists($file))
{
......
}
If is_valid($string) returns false, does the php interpreter still check later conditions, like up_to_length($string)?
If so, then why does it do extra work when it doesn't have to?
Yes, the PHP interpreter is "lazy", meaning it will do the minimum number of comparisons possible to evaluate conditions.
If you want to verify that, try this:
function saySomething()
{
echo 'hi!';
return true;
}
if (false && saySomething())
{
echo 'statement evaluated to true';
}
Yes, it does. Here's a little trick that relies on short-circuit evaluation. Sometimes you might have a small if statement that you'd prefer to write as a ternary, e.g.:
if ($confirmed) {
$answer = 'Yes';
} else {
$answer = 'No';
}
Can be re-written as:
$answer = $confirmed ? 'Yes' : 'No';
But then what if the yes block also required some function to be run?
if ($confirmed) {
do_something();
$answer = 'Yes';
} else {
$answer = 'No';
}
Well, rewriting as ternary is still possible, because of short-circuit evaluation:
$answer = $confirmed && (do_something() || true) ? 'Yes' : 'No';
In this case the expression (do_something() || true) does nothing to alter the overall outcome of the ternary, but ensures that the ternary condition stays true, ignoring the return value of do_something().
Bitwise operators are & and |.
They always evaluate both operands.
Logical operators are AND, OR, &&, and ||.
All four operators only evaluate the right side if they need to.
AND and OR have lower precedence than && and ||. See example below.
From the PHP manual:
// The result of the expression (false || true) is assigned to $e
// Acts like: ($e = (false || true))
$e = false || true;
// The constant false is assigned to $f before the "or" operation occurs
// Acts like: (($f = false) or true)
$f = false or true;
In this example, e will be true and f will be false.
Based on my research now, PHP doesn't seem to have the same && short circuit operator as JavaScript.
I ran this test:
$one = true;
$two = 'Cabbage';
$test = $one && $two;
echo $test;
and PHP 7.0.8 returned 1, not Cabbage.
No, it doesn't anymore check the other conditions if the first condition isn't satisfied.
I've create my own short-circuit evaluation logic, unfortunately it's nothing like javascripts quick syntax, but perhaps this is a solution you might find useful:
$short_circuit_isset = function($var, $default_value = NULL) {
return (isset($var)) ? : $default_value;
};
$return_title = $short_circuit_isset( $_GET['returntitle'], 'God');
// Should return type 'String' value 'God', if get param is not set
I can not recall where I got the following logic from, but if you do the following;
(isset($var)) ? : $default_value;
You can skip having to write the true condition variable again, after the question mark, e.g:
(isset($super_long_var_name)) ? $super_long_var_name : $default_value;
As very important observation, when using the Ternary Operator this way, you'll notice that if a comparison is made it will just pass the value of that comparison, since there isn't just a single variable. E.g:
$num = 1;
$num2 = 2;
var_dump( ($num < $num2) ? : 'oh snap' );
// outputs bool 'true'
My choice: do not trust Short Circuit evaluation in PHP...
function saySomething()
{
print ('hi!');
return true;
}
if (1 || saySomething())
{
print('statement evaluated to true');
}
The second part in the condition 1 || saySomething() is irrelevant, because this will always return true. Unfortunately saySomething() is evaluated & executed.
Maybe I'm misunderstood the exact logic of short-circuiting expressions, but this doesn't look like "it will do the minimum number of comparisons possible" to me.
Moreover, it's not only a performance concern, if you do assignments inside comparisons or if you do something that makes a difference, other than just comparing stuff, you could end with different results.
Anyway... be careful.
Side note: If you want to avoid the lazy check and run every part of the condition, in that case you need to use the logical AND like this:
if (condition1 & condition2) {
echo "both true";
}
else {
echo "one or both false";
}
This is useful when you need for example call two functions even if the first one returned false.

The strange ways of the "or" in PHP

PHP's or is an weird keyword. Here it is in a code snippet that makes me confused:
echo 0 or 1; // prints 1
$foo = (0 or 1);
echo $foo; // prints 1
$foo = 0 or 1;
echo $foo; // prints 0 for some reason
Why does the last one print 0 and not 1?
This is because of different operator precedence. In the third case, the assignment is handled first. It will be interpreted like this:
($foo = 0) or 1;
The || operator has a different precedence. If you use
$foo = 0 ||1;
It will work as you expect.
See the manual on logical operators
No, I wouldn't, that's because of operator precedence:
$foo = 0 or 1;
// is same as
($foo = 0) or 1;
// because or has lower precedence than =
$foo = 0 || 1;
// is same as
$foo = (0 || 1);
// because || has higher precedence than =
// where is this useful? here:
$result = mysql_query() or die(mysql_error());
// displays error on failed mysql_query.
// I don't like it, but it's okay for debugging whilst development.
It's ($foo = 0) or 1;. or has a lower operator precedence than = .
You should use || in this case, since it has a higher precedence than =, and thus will evaluate as you'd expect.
IIRC, the assignment operator (=) has higher precedence than or. Thus, the last line would be interpreted as:
($foo = 0) or 1;
Which is a statement that assigns 0 to $foo, but returns 1. The fist statement is interpreted as:
echo(0 or 1);
An as such will print 1.
Order of operations. The word "or" has much lower precedence than the corresponding "||". Lower, even, than the assignment operator. So the assignment happens first, and the value of the assignment is the first operand to the "or".
"or" is meant more to be used for flow control than for logical operations. It lets you say something like
$x = get_something() or die("Couldn't do it!");
if get_something is coded to return false or 0 on failure.
In the first two snippets, you are comparing 0 or 1 (essentially true or false). In the third snippet you are assigning 0, which works, and thus is true, so therefore the or condition is not executed.emphasized text
In your third example, the = operator has a higher precedence than or, and thus gets done first. The || operator, superficially the same, has a higher precedence than =. As you say, interesting.

'AND' vs '&&' as operator

I have a codebase where developers decided to use AND and OR instead of && and ||.
I know that there is a difference in operators' precedence (&& goes before and), but with the given framework (PrestaShop to be precise) it is clearly not a reason.
Which version are you using? Is and more readable than &&? Or is there no difference?
If you use AND and OR, you'll eventually get tripped up by something like this:
$this_one = true;
$that = false;
$truthiness = $this_one and $that;
Want to guess what $truthiness equals?
If you said false... bzzzt, sorry, wrong!
$truthiness above has the value true. Why? = has a higher precedence than and. The addition of parentheses to show the implicit order makes this clearer:
($truthiness = $this_one) and $that
If you used && instead of and in the first code example, it would work as expected and be false.
As discussed in the comments below, this also works to get the correct value, as parentheses have higher precedence than =:
$truthiness = ($this_one and $that)
Depending on how it's being used, it might be necessary and even handy.
http://php.net/manual/en/language.operators.logical.php
// "||" has a greater precedence than "or"
// The result of the expression (false || true) is assigned to $e
// Acts like: ($e = (false || true))
$e = false || true;
// The constant false is assigned to $f and then true is ignored
// Acts like: (($f = false) or true)
$f = false or true;
But in most cases it seems like more of a developer taste thing, like every occurrence of this that I've seen in CodeIgniter framework like #Sarfraz has mentioned.
Since and has lower precedence than = you can use it in condition assignment:
if ($var = true && false) // Compare true with false and assign to $var
if ($var = true and false) // Assign true to $var and compare $var to false
For safety, I always parenthesise my comparisons and space them out. That way, I don't have to rely on operator precedence:
if(
((i==0) && (b==2))
||
((c==3) && !(f==5))
)
Precedence differs between && and and (&& has higher precedence than and), something that causes confusion when combined with a ternary operator. For instance,
$predA && $predB ? "foo" : "bar"
will return a string whereas
$predA and $predB ? "foo" : "bar"
will return a boolean.
Let me explain the difference between β€œand” - β€œ&&” - "&".
"&&" and "and" both are logical AND operations and they do the same thing, but the operator precedence is different.
The precedence (priority) of an operator specifies how "tightly" it binds two expressions together. For example, in the expression 1 + 5 * 3, the answer is 16 and not 18 because the multiplication ("*") operator has a higher precedence than the addition ("+") operator.
Mixing them together in single operation, could give you unexpected results in some cases
I recommend always using &&, but that's your choice.
On the other hand "&" is a bitwise AND operation. It's used for the evaluation and manipulation of specific bits within the integer value.
Example if you do (14 & 7) the result would be 6.
7 = 0111
14 = 1110
------------
= 0110 == 6
which version are you using?
If the coding standards for the particular codebase I am writing code for specifies which operator should be used, I'll definitely use that. If not, and the code dictates which should be used (not often, can be easily worked around) then I'll use that. Otherwise, probably &&.
Is 'and' more readable than '&&'?
Is it more readable to you. The answer is yes and no depending on many factors including the code around the operator and indeed the person reading it!
|| there is ~ difference?
Yes. See logical operators for || and bitwise operators for ~.
Another nice example using if statements without = assignment operations.
if (true || true && false); // is the same as:
if (true || (true && false)); // TRUE
and
if (true || true AND false); // is the same as:
if ((true || true) && false); // FALSE
because AND has a lower precedence and thus || a higher precedence.
These are different in the cases of true, false, false and true, true, false.
See https://ideone.com/lsqovs for en elaborate example.
I guess it's a matter of taste, although (mistakenly) mixing them up might cause some undesired behaviors:
true && false || false; // returns false
true and false || false; // returns true
Hence, using && and || is safer for they have the highest precedence. In what regards to readability, I'd say these operators are universal enough.
UPDATE: About the comments saying that both operations return false ... well, in fact the code above does not return anything, I'm sorry for the ambiguity. To clarify: the behavior in the second case depends on how the result of the operation is used. Observe how the precedence of operators comes into play here:
var_dump(true and false || false); // bool(false)
$a = true and false || false; var_dump($a); // bool(true)
The reason why $a === true is because the assignment operator has precedence over any logical operator, as already very well explained in other answers.
Here's a little counter example:
$a = true;
$b = true;
$c = $a & $b;
var_dump(true === $c);
output:
bool(false)
I'd say this kind of typo is far more likely to cause insidious problems (in much the same way as = vs ==) and is far less likely to be noticed than adn/ro typos which will flag as syntax errors. I also find and/or is much easier to read. FWIW, most PHP frameworks that express a preference (most don't) specify and/or. I've also never run into a real, non-contrived case where it would have mattered.

Categories