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
Related
I had the following in my code:
$mixed = array();
$mixed[0] = "It's a zero!";
$mixed['word'] = "It's a word!";
foreach ($mixed as $key => $value) {
if ($key == 'word') {
echo $value.'<br />';
}
}
The above would for some reason print both "It's a zero!" and "It's a word!". I was expecting it to print only "It's a word!". Why is that?? I feel like I am missing something important. When I was using === in the if statement, it worked as expected, in other words it printed only "It's a word!". I know there's a difference between the equal and identical operators, but the first example is not equal is it?
== does the type-conversion for you before comparison.
When you did an == with an integer 0, it converted 'word' into the appropriate integer value.
intval() returns 0 when supplied a pure-string, so 0 matched. The other was matched in string-context, and that matched as well.
=== does no such implicit conversion, so it returned true only in one case, when the strings were actually identical.
PHP variables have type.
== checkes equality after conversion to the same type, === also checks the type. Use var_dump to see what the real types are.
See #Cthulhu 's answer above which is much clear.
Apart from that, here is a different example.
strpos() function returns the position of the needle from haystack.
<?php
$pos_a = strpos('apple', 'a'); // a is in the first position.
$pos_b = strpos('apple', 'b'); // there is no b.
if ($pos_a){
echo 'we got a!'."\n";
}
if ($pos_b){
echo 'we got b!'."\n";
}
strpos return FALSE if the needle is not found. But you will see that php does not run any echo statement.
If you var_dumo()'d these 2 values, you will see that $pos_a and $pos_b contain 0 and FALSE.
if statement just failed because 0 and FALSE both are considered FALSE unless you use ===
Now try this:
<?php
$pos_a = strpos('apple', 'a'); // a is in the first position.
$pos_b = strpos('apple', 'b'); // there is no b.
if ($pos_a !== FALSE){
echo 'we got a!'."\n";
}
if ($pos_b !== FALSE){
echo 'we got b!'."\n";
}
Now you will see the desired result as it echos "we got a!".
$a == $b Equal TRUE if $a is equal to $b after type juggling.
$a === $b Identical TRUE if $a is equal to $b, and they are of the same type.
it looks that
if you check 0 against a string with == then PHP returns true:
php -r 'var_dump(0 == "statuses");'
-> returns TRUE
but not if your string has a number at the beginning:
php -r 'var_dump(0 == "2statuses");'
-> returns FALSE
from the specs I get it that it attempts a conversion - in this case the string to number.
so better use ===
http://php.net/manual/en/language.operators.comparison.php
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
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)) { ... }
I know this must be a simple question, but I know that in PHP in a statement like this
if ($a && $b) { do something }
if $a is false PHP doesn't even check $b
Well is the same thing true about OR so
if ($a || $b) { do something }
If $a is true, does it still check $b
I know this is elementary stuff, but I can't find the answer anywhere... Thanks
Evaluation of logical expressions is stopped as soon as the result is known.
logical operators
See Example 1 on the Logical Operators page in the manual.
// --------------------
// 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());
Look at this example:
function foo1() {
echo "blub1\n";
return true;
}
function foo2() {
echo "blub2\n";
return false;
}
if (foo1() || foo2()) {
echo "end.";
}
$b / foo2() isnt checked.
Demo here: codepad.org
If at least one OR Operand is true, there is no need to go further and check the other operands and the whole thing will evaluate to true.
(a || b || c || d || e ||...) will be TRUE if at least one of the operands is true, thus once I found one operand to be true I do not need to check the following operands.
This logic applies everywhere, PHP, JAVA, C...
If you know your truth tables fairly well, then you can probably figure it out yourself. As others have said, PHP will evaluate until it is certain of an outcome. In the case of OR, only one has to be true for the statement to return true. So PHP evaluates until it finds a true value. If it doesn't find one, the statement evaluates to false.
<?php
if(true && willGetCalled()) {}
if(false && wontGetCalled()) {}
if(true || wontGetCalled()) {}
if(false || willGetCalled()) {}
?>
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.