I recently got into an argument over how switch handles comparisons, and need help settling it.
If I write a switch such as:
switch ($x){
case ($x > 5):
echo "foo";
break;
case ($x < 5):
echo "bar";
break;
default:
echo "five";
break;
}
Which if statement is it equivalent to? A or B?
// A
if ($x > 5) {
echo "foo";
} elseif ($x < 5) {
echo "bar";
} else {
echo "five";
}
// B
if ($x == ($x > 5)) {
echo "foo";
} elseif ($x == ($x < 5)) {
echo "bar";
} else {
echo "five";
}
To everyone, let me clarify:
It is equivalent to B.
It is not "both", it is not sometimes its one, sometimes it is the other, it is always B. To understand why you sometimes see results that indicate that it might be A, you need to understand how type coercion works in PHP.
If you pass in a falsey value to the "argument" of switch and you use expressions in your cases that result in a boolean value, they will only match if your expression evaluates to FALSE.
switch is basically a huge if/elseif tree that performs loose comparisons (== instead of ===) between the value passed to switch (the left side of the expression) and the expression in the cases (the right side).
This can be proved quite nicely with a variation on your code:
$x = 0;
switch ($x) {
case $x > -1: // This is TRUE, but 0 == FALSE so this won't match
echo "case 1";
case $x == -1: // This is FALSE, and 0 == FALSE so this will match
echo "case 2";
}
And if we convert that to the two if/elseif trees:
A:
$x = 0;
if ($x > -1) {
// It matches here
echo "case 1";
} else if ($x == -1) {
// and not here
echo "case 2";
}
B:
$x = 0;
if ($x == ($x > -1)) {
// It doesn't match here
echo "case 1";
} else if ($x == ($x == -1)) {
// ..but here instead
echo "case 2";
}
Your example is equivalent to B.
If you want to use comparison into your switch (and be equivalent to A), you could write this:
switch (true) { // Use true instead of $x
case ($x > 5):
echo "foo";
break;
case ($x < 5):
echo "bar";
break;
default:
echo "five";
break;
}
That switch case is equivalent to B
Edit :
If we take for example that $x is equal to 0 :
$x > 5 will evaluate to false (and 0 evaluates to false too), so the first if will print bar, but the second one will print foo.
The switch will be transformed to something like this :
switch ($x){
case false:
echo "foo";
break;
case true:
echo "bar";
break;
default:
echo "five";
break;
}
and that will print foo (same as B)
Edit 2 :
I tried it so that gave me :
with $x = 0 => switch (foo), if A (bar), if B (foo)
with $x = 5 => switch (five), if A (five), if B (five)
with $x = 7 => switch (foo), if A (foo), if B (foo)
Related
<?php
$x = 1;
if ($x == 2)
print "hi" ;
else if($x = 2)
print $x;
else
print "how are u";
?>
Apologies for this basic question as I am a beginner at php.
I was expecting the else statement to be executed and print "how are u", but it executed the elseif statement and printed '2' instead. May I ask why does $x become assigned to 2? Thanks in advance.
<?php
$x = 1;
if ($x == 2)
print "hi" ;
else if($x = 2) /* you assign $x 2 and it's true */
print $x;
else
print "how are u";
?>
In the elseif you are asigning the number 2 to $x which will always return true. Because of that it will never go to the else block.
Dont use = when doing comparisons but == or ===.
<?php
$x = 1;
if ($x == 2)
print "hi" ;
else if($x == 2)
print $x;
else
print "how are u";
?>
this is the right way to do it. Also it doesnt make sense to check both in if and elseif that $x == 2 since it will never execute the elseif block.
Let me try to explain it better, if you do:
if ($x = 2)
thats will assign 2 to $x and this is then the same as:
if ($x)
since the $x now holds the number 2 this is also the same as:
if (2)
this is always true so it will never go to further checks no matter what the number is.
You are SETTING x=2 in your else if --> else if($x = 2) -- This would be more appropriate .. Check for absolute === .. Then check for truthy == .. IE
<?php
$x = 1;
if ($x === 2)
print "hi" ;
else if($x == 2)
print $x;
else
print "how are u";
?>
Conversely .. You can play with truthy vs absolute by comparing an integer to string too .. Like:
<?php
$x = 2;
if ($x === 2) // Will return true
print "Is absolute integer" ;
else if($x == 2) // Will return true
print "Is truthy integer";
else if($x === '2') // Will return false
print "Is absolute string";
else if($x == '2') // Will return true
print "Is truthy string";
else
print "how are u";
?>
Which will never reach the else .. But you can see how operators can make or break a program ..
This is because = is assignment operator not comparison like ==. That is why $x is assigned value 2 and the else if condition is met and executed.
It is possible to go to default case from within some other case like this?
$a = 0;
$b = 4;
switch ($a) {
case 0:
if ($b == 5) {
echo "case 0";
break;
}
else
//go to default
case 1:
echo "case 1";
break;
default:
echo "default";
}
I tried to remove the else and was expecting that it would continue evaluating all following cases until default but it gets into case 1 then. Why is it so and how can I get to the default one?
Yes you can if you reorder the case statements:
switch ($a) {
case 1:
echo "case 1";
break;
case 0:
if ($b == 5) {
echo "case 0";
break;
}
default:
echo "default";
}
Why is it so:
it is defined, if you de not have a break statement the next case will be executed. If there is no more case, the default will be executed if one is defined
You could re-order the case statements to allow a fall through to the next option, but if there are several times you wish to do this it can become impossible or just very fragile. The alternative is to just more the common code into a function...
function defaultCase() {
echo "default";
}
switch ($a) {
case 0:
if ($b == 5) {
echo "case 0";
}
else {
defaultCase();
}
break;
case 1:
echo "case 1";
break;
default:
defaultCase();
}
I would suggest using a simple if / else as I mentioned in the comments.
However, here's another way you could do it using a switch statement, if that helps:
switch ([$a, $b]) {
case [0, 5]:
echo 'case 0';
break;
case [1, $b]:
echo 'case 1';
break;
default:
echo 'default';
}
I don't want to repeat the same statements over and over again.
What is the best way to do this?
<?php
if ($a = '3'){
statement 1;
statement 2;
statement 3;
}else if ($a = '2'){
statement 1;
statement 2;
}else if ($a = '1'){
statement 1;
}
?>
To avoid repetitions, you can code:
<?php
($a == '3' or $a == '2' or $a == '1') and statement 1;
($a == '3' or $a == '2' ) and statement 2;
($a == '3' ) and statement 3;
?>
Or, that is the same:
<?php
if ($a == '3' or $a == '2' or $a == '1') { statement 1 ; }
if ($a == '3' or $a == '2' ) { statement 2; }
if ($a == '3' ) { statement 3; }
?>
Also, take a look to Switch statement
Quoting php doc:
The following two examples are two different ways to write the same
thing, one using a series of if and elseif statements, and the other
using the switch statement:
<?php
if ($i == 0) {
echo "i equals 0";
} elseif ($i == 1) {
echo "i equals 1";
} elseif ($i == 2) {
echo "i equals 2";
}
switch ($i) {
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
}
?>
For your code:
<?php
switch ($a) {
case '3':
statement 1;
statement 2;
statement 3;
break;
case '2':
statement 1;
statement 2;
break;
case '3':
statement 1;
break;
}
?>
<?php
for ($i = 1; $i <= $a; $i++) {
echo $statement . $i;
}
As danihp mentioned, you can use switch. Here's another way without breaks. The downfall of this approach is that you need to create a case for every possible value for $a.
<?php
switch ($a) {
case '3':
statement 3;
case '2':
statement 2;
case '1':
statement 1;
break;
default:
break;
}
A sample of what I'm trying to do will be more explicit:
var_dump($opti_point); //int 0
if ($opti_point>=0 && $opti_point < 25) echo 'good';//echoing good
switch ($opti_point) {
case ($opti_point>= 0 && $opti_point < 25):
$test = 0;
break;
case ($opti_point >= 25 && $opti_point < 50):
echo 'we are in this case'; // This case is called !
$test = 2;
break;
default:
test = 0;
break;
}
Is there a trick here ?
thx
You cannot put comparisons inside "case" unfortunately...
A switch is only used when a value can have one of a limited number of values like so:
switch ( $val ) {
case 1:
echo "Got 1";
break;
case 2:
echo "Got 2";
break;
default:
echo "Got invalid value";
}
A workaround would be to use:
switch (true) {
case ($opti_point>= 0 && $opti_point < 25):
$test = 0;
break;
case ($opti_point >= 25 && $opti_point < 50):
echo 'we are in this case';
$test = 2;
break;
default:
test = 0;
break;
}
Which will work, but is a bit ugly...
Also, you're missing a single quote in echo we are in this case'; which should be echo 'we are in this case';
You should be using an if instead =)
You need to change the switch argument to true of false if you do comparison liek that in the cases.
You are not comparing what you think you are comparing. This is the code I think you want.
var_dump($opti_point); //int 0
if ($opti_point>=0 && $opti_point < 25) {
$test = 0;
echo 'You are now here!';
} elseif ($opti_point >= 25 && $opti_point < 50) {
$test = 2;
} else {
test = 0;
}
In your example, you are comparing the result of the logical statement...
($opti_point>=0 && $opti_point < 25) // true
To the value of $opti_point
0 // false
So PHP is actually converting what you think in an integer into a boolean to compare it with the result of the conditional statement.
I think that's a very bad way to use a switch statement, you should not put conditional sentences in the cases... In fact, I'm sure that that would be illegal in other languages and I'm not sure that it should work in PHP. Use a number of concatenated if-else conditions instead:
if ($i == 0) {
echo "i equals 0";
} elseif ($i == 1) {
echo "i equals 1";
} elseif ($i == 2) {
echo "i equals 2";
}
I'll go true the code with you
var_dump($opti_point); //int 0 , or false --- you should use TRUE
if ($opti_point>=0 && $opti_point < 25) echo 'good';//echoing good
switch ($opti_point) { // chose the case that is $opti_point (0 or false)
case ($opti_point>= 0 && $opti_point < 25): // true, so go to next
$test = 0;
break;
case ($opti_point >= 25 && $opti_point < 50): //false si this is the wan I pick
echo 'we are in this case'; // This case is called !
$test = 2;
break; // ingore the rest
default:
test = 0;
break;
}
you should use TRUE in the switch
if this is the exact code then try this
var_dump($opti_point); //int 0
if ($opti_point>=0 && $opti_point < 25) echo 'good';//echoing good
switch ($opti_point) {
case ($opti_point>= 0 && $opti_point < 25):
$test = 0;
break;
case ($opti_point >= 25 && $opti_point < 50):
echo 'we are in this case'; // This case is called !
$test = 2;
break;
default:
$test = 0;
break;
}
You have a misunderstanding on how switch-case works. Case DOES NOT TEST YOUR EXPRESSION TO BE boolean TRUE!
It compares its value to 'switch' value!
Here is an explanation:
$opti_point>= 0 && $opti_point < 25 evalutes to true which integer representation is 1 and since PHP can deal with types on it's own, it turnes true to 1 and compares it with value in switch which is 0
$opti_point >= 25 && $opti_point < 50 evaluates to false which is 0 as integer, so... that's your case ;)
Is there a way to include multiple cases inside a switch method in php?
The switch statement works by evaluating each case expression in turn and comparing the result to the switch expression. If the two expressions are equivalent, the case block is executed (within the constraints established by break/continue constructs). You can use this fact to include arbitrary boolean expressions as case expressions. For example:
<?php
$i = 3;
$k = 'hello world';
switch (true) {
case 3 == $i and $k == 'hi there';
echo "first case is true\n";
break;
case 3 == $i and $k == 'hello world';
echo "second case is true\n";
break;
} //switch
?>
This outputs:
second case is true
I don't use this sort of construction very often (instead preferring to avoid such complex logic), but it sometimes comes up where a complicated if-then statement might otherwise be used, and can make such snippets much easier to read.
What's wrong with simply nesting switches?
$i = 1;
$j = 10;
switch($i) {
case 2:
echo "The value is 2";
break;
case 1:
switch($j) {
case 10:
echo "Exception Case";
break;
default:
echo "The value is 1";
break;
}
break;
default:
echo "Invalid";
break;
}
Yes it is possible
Here is an example to start with
<?
$i = 1;
$j = 10;
switch($i) {
case "2":
echo "The value is 2";
break;
case ($i==1 && $j==10):
echo "Your exceptional Switch case is triggered";
break;
default:
echo "Invalid";
break;
}
?>