<?php
$var = 0;
switch($var) {
case "a":
echo "I think var is a";
break;
case "b":
echo "I think var is b";
break;
case "c":
echo "I think var is c";
break;
default:
echo "I know var is $var";
break;
}
?>
Maybe someone else will find this fascinating and have an answer. If you run this, it outputs I think the var is a when clearly it's 0. Now, I'm most certain this has something to do with the fact that we're using strings in our switch statement but the variable we're checking is an integer. Does anyone know why PHP behaves this way? It's nothing too major, but it did give me a bit of a headache today.
Thanks folks!
If you compare an integer with a string, the string is converted to a number. So effectively your snippet is equivalent to:
$var = 0;
switch($var) {
case 0: // "a" gets converted to 0.
echo "I think var is a";
break;
case 0: // "b" gets converted to 0.
echo "I think var is b";
break;
case 0: // "c" gets converted to 0.
echo "I think var is c";
break;
default:
echo "I know var is $var";
break;
}
Which will produce I think var is a as output as the first case body gets executed. Even though there are 3 candidates, the first one is selected because it appears at the top.
In PHP, when you compare a string and an integer, whether it be in a switch statement or using the regular comparison operators, the string is converted to an integer (unless you're using the === operator).
And when converting a string to an integer, a string that doesn't start with either a digit or a sign is always converted to 0.
See the documentation here and here.
Related
Why does the following code trigger the first case, instead of the one that actually matches.
switch (0) {
case 'test':
echo 1;
break;
case 0:
echo 2;
}
result: 1
It seems to be something with 0. If i try switch(1) I get nothing, and switch(2) will trigger case 0 which is expected.
This is in php 7 on both mac and debian.
You are comparing an integer to a string. This can't be done, so PHP does an implicit type cast.
PHP picks the cast to integer and converts 'test'.
And (int)'test' is 0. Therefore the first statement matches.
This could get even weirder:
switch (1) {
case '1test':
// would also match
break;
}
Can someone please explain why the case "a" is never reached in below code and why it will always execute case 0
switch ("a") {
case 0:
echo "0";
break;
case "a": // never reached because "a" is already matched with 0
echo "a";
break;
}
PHP, like JavaScript or Perl, is a loosely-typed language and will attempt to guess what you want to do. In this case, it changed your string to the closest integer it could find, which is zero. In other words, "a" == 0 is a true statement in PHP.
More on this topic can be found in the PHP documentation. I suggest you typecast the value in the switch statement, or replace it with an if/elseif/else construct.
As of PHP 8.0, this behaviour has changed and now the integer value will always be changed to a string before comparison between the two types. Strictly typing and comparing your variables remains the recommended practice, however.
You can not used mix-cases in a switch statement as PHP will interpret the meaning of what you mean.
In layman's terms, it will try to find the 'value of "a"' which is not defined to the processor, and hence is 0 in this case.
Same will go for the code below:
<?php
$x = "a";
switch($x)
{
case "c":
echo "c";
break;
case 1:
echo "1";
break;
case 0:
echo "0";
break;
case "a":
echo "a";
break;
case false:
echo "false";
break;
default:
echo "def";
break;
}
?>
Documentation is available at PHP.net
The reason for this is because switch uses a loose comparison ==
That said:
if ("a" == 0) // TRUE
if ("a" == true) // TRUE
Pretty much anything else will evaluate to false. (except "a" == "a")
So, if you have the need to compare against both strings and integers, you should just convert to string for the comparison.
//$var = "a";
$var = 0;
$var = strval($var);
switch ($var) {
case '0':
echo "0";
break;
case 'a':
echo "a";
break;
}
The variable type used on case() should be same type used in switch().
<?php
switch ("a") {
case "0":
echo "0";
break;
case "a": // never reached because "a" is already matched with 0
echo "a";
break;
}
For integer type:
<?php
switch (1) {
case 0:
echo 0;
break;
case 1: // never reached because "a" is already matched with 0
echo 1;
break;
}
Expect you have following situation:
$myVar = null;
switch($myVar) {
case is_int($myVar):
echo "i am an int";
break;
case null:
echo "i am null";
break;
default:
echo "failure";
}
The result is "i am an int". But I expected "i am null" as a result.
Is this a bug in php (my version: 5.5.11) or natural behaviour?
switch($myVar) means test the value of $myvar against each case expression until a match is found.
is_int($myVar) returns a Boolean false when $myvar is null.
Loose comparison of null against Boolean false (null will be converted to a Boolean false for the comparison) returns a true, so the case is accepted
You can get round this by changing the order of your case statements to test the null case first, but
Moral: It's never a good idea to use expressions in case statements
Why dont you use gettype() to identify the data type of the variable.
$myvar = null;
echo gettype($myvar)."\n";
$myvar = 1;
echo gettype($myvar)."\n";
$myvar = "a";
echo gettype($myvar);
DEMO
I have this code:
$r = do_something($data);
if ($r == 1)
{
echo "it is 1";
}
switch ($r)
{
case "a":
print "a";
break;
case "b":
print "b";
break;
default:
print "default";
}
With this code the output should be:
it is 1
default
but the surprise is that the output is:
it is 1
a
How is this possible?
edit: after some test i see that:
$r === true.
so the new question is: when the var is true how work the switch?
PHP's "type juggling" rules are rather tricky, and occasionally unintuitive and even controversial. There's a great big table in the manual showing what happens when you make comparisons of various sorts, but to explain your particular case:
You are working with three different types: $r is currently true, which is a boolean; the if statement tests against 1, which is an integer; and the switch statement tests against "a" and "b", which are strings.
When you compare a boolean to an integer, PHP first converts the integer to a boolean, using the rule that 0 converts to false, and anything else converts to true. This has the effect in your case of $r == 1 evaluating to true, but $r == 42 would also evaluate to true.
When you compare a boolean to a string, a similar thing happens, but here the string gets converted according to this rule: an empty string is false, anything else is true. So $r == "a" also evaluates to true in your example, which is why that branch of the switch statement is executed.
To get the result you were hoping for, you need to force the type conversion to happen in a different way. There are a few ways to do this, but the simplest in your case is to cast $r to the same type as what you're comparing it against:
(int)$r will give you the integer 1 for a value of true, and 0 for false, so if ( (int)$r == 1 ) will give the same result, but be clearer that $r wasn't actually an integer at that point in the code.
more importantly, (string)$r will give you the string "1", so switch( (string)$r ) won't have to do any "type juggling" to compare against strings like "a" and "b", and you won't get any surprises there.
I think your do_something($data) function returns 1 if it does what it suppose to do. I tried this code and it works. Here it is.
function do_something($data){
return 1;
}
$r= do_something('abc');
if ($r == 1)
{
echo "it is 1<br />";
}
switch ($r)
{
case "a" : print "a"; break;
case "b" : print "b"; break;
default : print "default";
}
OUTPUT:
it is 1
default
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
PHP expresses two different strings to be the same
I have a problem understanding what's causes this weird behavior in a switch case instruction.
The code is this:
<?php
$myKey = "0E9";
switch ($myKey) {
case "0E2":
echo "The F Word";
break;
case "0E9":
echo "This is the G";
break;
default:
echo "Nothing here";
break;
}
?>
The result of this instruction should be This is the G
Well, not so. always returns The F Word
If we reverse the 0E9 left instructions for the beginning and try to find the value 0E2
<?php
$myKey = "0E2";
switch ($myKey) {
case "0E9":
echo "The G String";
break;
case "0E2":
echo "The F Word";
break;
default:
echo "Nothing here";
break;
}
?>
Now returns always This is the G
0E2 and 0E9 values are not interpreted as text? Those Values are reserved?
Someone can explain this behavior?
"0E2" == "0E9" is true because they are numerical strings.
Note: switch use loose comparision.
Check this question: PHP expresses two different strings to be the same.
Numeric strings such as these are equal to each other .. always. Unfortunately, there is no way to force an equivalence comparison via switch. You just have to use if:
if ($myKey === '0E9') {
echo 'g';
}
else if ($myKey === '0E2') {
echo 'f';
}
else {
echo "Nothing here";
}
You could also trim the leading zero, I suppose.