can this conditional logic work in PHP? - php

I came across some code today where a string is compared to two values at the same time. I've never seen this before - will this work? Can someone explain it to me?
$foo = 'date';
if ($foo == ('date' || 'datetime')) {
echo "Hello world";
}

That won't work. Write if ($foo == 'date' || $foo == 'datetime').
Not only won't || work for selecting from a set, but also you use used a single =, which is for assignment rather than comparison.
In this case, the constant strings are compared using the boolean or operator. To do that, they are both converted to boolean. Since they are non-empty strings, they evaluate to true. true or true returns true, which is assigned to $foo which is compared to $foo. That comparison will always be true if $foo is 'date' or 'datetime' or about any other non-empty string.
So, whatever the previous value of $foo was, or even if it wasn't assigned at all, the if-expression always evaluates to true, so you always get the echo, and $foo will always be true afterwards.

This'll not work. ('date' || 'datetime') always evaluates to true.
Use this instead:
$foo = 'date';
if ($foo == 'date' || $foo == 'datetime') {
echo "Hello world";
}

You could try the following:
$haystack = array("date","datetime");
$needle = "date";
if (in_array($needle,$haystack)) {
// do something
}

No. the || or OR operators only work with Booleans. you'll need this condition:
if ($foo == 'date' || $foo == 'datetime') { ... }
But what if you have 10 possible values? You'll need one for each? yes and no.
Another possibility is to insert all the possible values into an array and check whether your value is possible by comparing it to that array, using in_array():
$possible_values = array('date', 'datetime');
if (in_array($foo, $possible_values)) { ... }

Related

how ordering makes a difference within an expression for an if statement

I have an array ...
$a= array(1,2,3,4);
if (expr)
{ echo "if";
}
else
{ echo 'else';
}
When expr is ( $a = '' || $a == 'false') , output is "if" ,
but when expr is ( $a == 'false' || $a = '' ) , output is "else"
Can anyone explain why & how ordering makes a difference ??
Edit : I understand that I am assigning '' to $a. That is not the problem. The real question is : What does the expression $a = '' return? And why does reversing the order of the 2 situations switch us from the IF section to the ELSE section?
AGAIN : I UNDERSTAND I AM ASSIGNING NOT COMPARING. PLEASE ANSWER THE QUESTION AS IS.
First, never use = as a comparison operator. It is an assignment operator.
The difference is that false (as a boolean) is not the same as 'false' as a string.
Certain expressions are type juggled by PHP to evaluate somewhat differently to how you would expect.
false==""
// TRUE.
false=="false"
// FALSE.
Additionally, when you try to compare numbers to strings, PHP will try to juggle the data so that a comparison will be performed. There is a lot to it (much more than I will post here) but you would do well to investigate type juggling and various operators. The docs are a great start for this. You should also have a read of the comparison operators which go into a lot of detail about how various comparisons will work (depending on whether you use == or === for example).
With $a = '' you are setting $a to an empty string. This is the same as:
$a = '';
if($a){
echo 'if';
}
The || operator checks if the first condition is true and if it is, it continues with the code in the brackets. In PHP, if $a is set to anything, it will return true. In the second case $a does not equal the string 'false' (you are not comparing it to a boolean false even!), so it executes the code in the else part.
And Fluffeh is not entirely correct. You can use the assignment operator in an if condition very effectively, you just have to be smart about it.
$a = '' is an assignment: you have, in error, used = in place of ==. Assignment is an expression which has the value of the thing your assigning.
A single equals sign = is the assignment opporator, so $a = '' is assigning an empty string to $a not checking if it is equal to.
In your 1st example you set the value of $a to an empty string, then check if it is false. An empty tring evalutes to false in php, so the conditional is true.
In your second example, you check if $a equals false 1st (when the value of $a is an array), so the conditional is false

simple if statements (not short hand)

So today, as everyday, I was programming. Going along my usual business, typing away, listening to Daft Punk and various other groovy tunes. Then out of the blue, I had to write something along the lines of:
$x = 'a'; // For instance
if ($x == 'a' || $x == 'b') {
// ...
}
Simple enough, not too shabby I say. But wait! I thought to myself "there must be an easier way to do that - I'm repeating myself". So I set about attempting to solve this with the following code:
if ($x == ('a' || 'b')) {
// ...
}
However, that doesn't work. At all. It's always true. If $x is equal to a, b, c or cake. So I sulked, cried a little bit and have decided to ask Stackoverflow if any of you guys know why.
Thanks!
|| is the logical or, it evaluates the left side as boolean ('a', which is in boolean context true) and if that's true returns true, if not, it does the same thing for the right hand side.
var_dump('a' || 'b');
bool(true)
Now, this value is compared against a character, which, based on the crazy rules of PHP (loose comparison chart), will also be true:
var_dump('a' == true);
bool(true)
You're asking PHP to evaluate if $x is equal to the value of ('a' OR 'b'), which will ALWAYS return true since both 'a' and 'b' have nonzero values.
You must use the comparison operator individually in this case, or use nickb's suggestion from the comments.
It didn't worked because
$a = 'a' || 'b'; // true, since 'a' and 'b' considered truthy
In this case, your string literals will be converted to booleans.
And if your $x in the if is not an empty string or other string considered falsy they will be equal.
However you can write your if like this:
if (in_array($x, array('a', 'b', 'cake'))
If you feel that it makes your intent more clear.
I would do:
$valid = array('a', 'b');
if (in_array($x, $valid)) {
...
}
Simple enough!
...but, in retrospect, maybe you didn't want another way to do it?
As you know || is a logical operator and always return true or false(in another word 1 or 0).
So, code ('a' || 'b') always return true(1). In this above case $x contains value so due to automatic type conversation $x also set to true(1) so its if(1 == 1) and return always true.
try with bellow code
$x = false;
if ($x == ('a' || 'b')) { echo 'true'; } else{ echo 'false';}
Always return false.
See how php converts strings to boolean
php > var_dump((bool) "a");
bool(true)
php > var_dump((bool) "b");
bool(true)
php > var_dump((bool) "cake");
bool(true)
So basically you asking php if($x == true)
see http://php.net/manual/en/types.comparisons.php

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.

EASY! But which conditional statement works

Simple but this has always bothered me. Which is the best way to condition statement?
$foo = '1';
if($foo === '1' || $foo === '2' || $foo === '3')
{
// foo matches
}
or
if($foo === '1' || '2' || '3')
{
// foo matches
}
Which step works and is better. is there a better solution?
The second version will always evaluate to true.
If you want to compact the comparison against multiple alternatives then use:
if (in_array($foo, array('1', '2', '3') )) {
If you want to closely match the exact comparison === then you would however need:
if (is_string($foo) && in_array($foo, array(...))) {
$foo = 1;
if(in_array($foo, array(1, 2, 3))){
//foo matches
}
This is an alternative:
if($foo>0 && $foo<4){
}
Second if statement won't work. PHP doesn't work like that. Any number other than 0 (including negatives) evaluates to true when alone in an if statement. This is why you can do something like if(count($array)) without specifying that count($array) must be greater than 0.
Would be the same as if you had said:
if($foo === 1)
{}
elseif(2) //This will always trigger if $foo !== 1.
{}
elseif(3) //This will never trigger because of the last one
{}
Each condition is it's own self contained condition. Instead of reading it as just "or" or "and" read it as "or if" and "and if". So if $foo is 1 or if 2 or if 3 instead of if $foo is 1 or 2 or 3
If it's just numeric, then amosrivera's solution is the best. If it's for other types of data, then webarto/mario have a good solution.

Categories