php logical operator comparison evaluation - php

here is what i'm trying to achieve:
if $x is either of these 3 values: 100, 200 or 300 - do something
I'm doing this:
if($x==("100"||"200"||"300"))
{
//do something
}
but //do something is executed even if $x is 400
I noticed that this works:
if($x=="100"||$x=="200"||$x=="300")
{
//do something
}
How is the first block of code different from the second block of code? What am I doing wrong?

The reason why your code isn't working is because the result of the expression:
('100' || '200' || '300')
is always TRUE because the expression contains at least one truthy value.
So, the RHS of the expression is TRUE, while the LHS is a truthy value, therefore the entire expression evaluates to TRUE. The reason why this is happening is because of the == operator, which does loose comparison. If you used ===, the resulting expression would always be FALSE. (unless of course the value of $x is false-y.)
Let's analyze this:
Assuming $x equal '400':
($x == ('100'||'200'||'300'))
// ^ ^
// true true
Make sense now?
Bottom line here is: This is the wrong way of comparing 3 values against a common variable.
My suggestion is that you use in_array:
if(in_array($x, array('100', '200', '300')) {
//do something...
}

you can take all values in array it is working Perfectly.
$x=400;
if(in_array($x, array('100', '200', '300'))) {
echo $x.'is in array';
} else {
echo $x.'is not in array';
}

Related

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.
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.

Why does this PHP assignment in a loop always print the first value?

I'm very confused as to the output of this small piece of test code:
<?php
$count = 0;
while ($fn_retval = do_the_thing($count) !== false) {
print $fn_retval."\n";
$count++;
}
function do_the_thing($count) {
if ($count > 3) {
return false;
} else {
return $count;
}
}
?>
The output is:
$ php ./test.php
1
1
1
1
So it is correctly performing 4 iterations but always printing the return value of the first iteration. I feel like I must have missed something really obvious because this makes no sense.
Can somebody explain what's going on here because it seems like I can't use that assign-and-check construct in the way I thought I could.
The problem is that the order in which
$fn_retval = do_the_thing($count) !== false
is evaluated. If you check the Operator Precedence, you will see that !== is a higher precedence than =, so it's evaluated as
do_the_thing($count) !== false
and the result is then assigned to $fn_retval.
To force the order you are after, use brackets to explicitly do the assignment first...
while (($fn_retval = do_the_thing($count)) !== 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

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.

PHP if condition with strings

I am trying to write would be a simple if condition.
function genderMatch($consumerid1, $consumerid2)
{
$gender1=getGender($consumerid1);
$gender2=getGender($consumerid2);
echo $gender1;
echo $gender2;
if($gender1=$gender2)
echo 1;
return 1;
else
echo 0;
return 0;
}
The output of the getGender function is either a M or F. However, no matter what I do gender1 and gender2 are returned as the same. For example I get this output: MF1
I am currently at a loss, any suggestions?
if ($gender1 = $gender2)
assigns the value of $gender2 to $gender1 and proceeds if the result (i.e. the value of $gender2) evaluates to true (every non-empty string does). You want
if ($gender1 == $gender2)
By the way, the whole function could be written shorter, like this:
function genderMatch($cid1, $cid2) {
return getGender($cid1) == getGender($cid2);
}
You have to put two == for comparison. With only one, as you have right now, you are assigning the value to the first variable.
if($gender1=$gender2)
would become
if($gender1==$gender2)
this:
if($gender1=$gender2)
should be
if($gender1==$gender2)
notice the extra ='s sign. I think you might also need curly brackets for multiple lines of an if/else statement.
Your using the assignment operator = instead of comparsion operators == (equal) or === (identical).
Have a look at PHP operators.
You have some structural problems with your code as well as an assignment instead of a comparison.
Your code should look like this:
function genderMatch($consumerid1, $consumerid2){
$gender1=getGender($consumerid1);
$gender2=getGender($consumerid2);
echo $gender1;
echo $gender2;
if($gender1==$gender2){
echo 1;
return 1;
}else{
echo 0;
return 0;
}
}
Notice the double '=' signs in the if statement. This is a comparison. A single '=' is an assignment. Also, if you want to execute more than 1 line of code with an if/else, you need brackets.
You are using a single = which sets the variable, ie. the value of $gender1 is set to be the value of $gender2.
Use the === operator instead: if($gender1 === $gender2). It is usually a good idea to do strict comparisons rather than loose comparisons.
Read more about operators here: php.net
Another alternative is to use strcmp($gender1, $gender2) == 0. Using a comparer method/function is more common in languages where the string-datatype isnĀ“t treated as a primary data-type, eg. C, Java, C#.

Categories