php switch strange anomaly - php

I have this code where $difference=0
switch ($difference)
{
case 0<=$difference && $difference<300:
return "A";
break;
case 300<=$difference && $difference<600:
return "B";
break;
}
I think that switch must return A but it returs B. Whats wrong ???

I'm posting this merely as informative.
Switches can be used with expressions, however this is tricky to do:
<?php
$value = 300;
$other = 1;
switch (true) {
case $value <= 300 && $other:
$var = 'A';
break;
case $value >= 300 && !$other:
$var = 'B';
break;
case $value >= 300 && $other:
$var = 'C';
break;
case $value > 300 && $other:
$var = 'D';
break;
default:
$var = 'FALSE';
break;
}
echo $var;
The above code will display 'C' correctly. A combination of if/else statements is equivalent but I tend to find the switch more readable. Be sure to always include a default case whose value you can rely on (or maybe return from the function, throw an exception, etc).
You can also compare other variables, types, call functions (although not recommended), etc to match the value declared in the switch statement (in this case, true but can be an integer, string or any other base type).

Switches with expressions like you are using will not be evaluated as you might think. Use an if statement instead:
if(0<=$difference && $difference<300)
{
return "A";
}
else if(300<=$difference && $difference<600)
{
return "B";
}

In this case what is happening is $difference being equal to 0 is being interpreted as false. Thus you have switch(false). Each case is evaluated as a whole and there for case 2 actually returns false thus matching the switch statements evaluation and returning B. It also has to do with loose type checking. PHP.net

Related

Please explain why PHP switch case is always executing case 0 in this code

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;
}

How to use switch with integer 0 in PHP?

having the integer 0 as switch parameter will take the first result "foo":
$data=0; // $data is usually coming from somewhere else, set to 0 here to show the problem
switch ($data) :
case "anything":
echo "foo";
break;
case 0:
echo "zero";
break;
default:
echo "bar";
endswitch;
How do I change this, so the switch will write "zero" as expected?
The switch/case statement uses loose comparison, and, like it or not, 0 == "anything" is true:
Comparison Operators
[...] If you compare a number with a string or the comparison involves
numerical strings, then each string is converted to a number and the
comparison performed numerically. These rules also apply to the switch
statement. [...]
var_dump(0 == "a"); // 0 == 0 -> true
One solution is to change all case statements to string, and do a string comparison:
$data = 0;
switch ((string) $data): ## <- changed this
case "anything":
echo "foo";
break;
case "0": ## <- and this
echo "zero";
break;
default:
echo "bar";
endswitch;
Switch/case statement uses "loose-comparison" (i.e. ==. in this case, 0 also means false and 1 also means true. (http://www.php.net/manual/en/types.comparisons.php#types.comparisions-loose)
To avoid this problem, two solutions:
1) As suggested by #zzlalani, add quotes.
case '0': ...
2) Explicitly cast the switch statement to force a strict comparison (===)
switch((string)($data)) { ... }
Do like this
$data=0;
switch ($data)
{
case 0:
echo "bar";
break;
default:
echo "foo";
break;
}
EDIT :
How do I change this, so the switch will write "zero" as expected?
You need to move your case statement above.
$data=0;
switch ($data) :
case 0: // Moved this case to the begining
echo "zero";
break;
case "anything":
echo "foo";
break;
default:
echo "bar";
endswitch;
This is because switch does not do a "strict-type" checking.

PHP check infinity inside switch

The following code:
switch ($value) {
case INF: $x = 'INF';
break;
case -INF: $x = '-INF';
break;
case NAN: $x = 'NaN';
break;
default: break;
}
doesn't work as I expected. I know that there are functions like is_infinite() but am I able to check variable infinity inside a switch statement?
My input can be any simple value (i.e. not an array and not an object). Could be integer, float, string, whatever.
am I able to check variable infinity inside a switch statement?
No. Switch statements work with constants, not with expressions.
if (is_infinite($value) || is_nan($value)) {
$x = (string)$value;
}
It's less lines of code, too.

PHP switch and case logical control

It possible to have logical control on case ?
ie:
$v = 0;
$s = 1;
switch($v)
{
case $s < $v:
// Do some operation
break;
case $s > $v:
// Do some other operation
break;
}
Is there a way to do something similar ?
The condition that is passed to switch is a value the cases are compared against. The condition (in your question $v) is evaluated once and then PHP seeks for the first case that matches the result.
From the manual (after Example #2), emphasis added:
The switch statement executes line by line (actually, statement by statement). In the beginning, no code is executed. Only when a case statement is found with a value that matches the value of the switch expression does PHP begin to execute the statements. PHP continues to execute the statements until the end of the switch block, or the first time it sees a break statement.
In your question switch ($v) is same as if you'd written: switch (0), because $v = 0. Then, your switch will try to find a case which equals to 0. And, just as #Kris said:
$s < $v evaluates to false, which triggers on the $v because it is 0 in here.
If you have to use conditions in case statements, your switch-condition should be a boolean, e.g.:
$v = 0;
$s = 1;
switch (true) {
case ($s < $v):
echo 's is smaller than v';
break;
case ($s > $v):
echo 's is bigger than v';
break;
}
Now your switch tries to seek the first case that evaluates to true, which in this case would be $s > $v.
Note that while the switch-condition is evaluated only once, cases are each evaluated in order:
$a = 1;
switch ($a) {
case 2:
echo 'two';
break;
case (++$a > 2):
break;
default:
echo $a;
}
echoes '2' from default-case, because when comparing $a to "2" $a was 1 and the case is discarded; while:
$a = 1;
switch ($a) {
case (++$a > 2):
break;
case 2:
echo 'two';
break;
default:
echo $a;
}
echoes 'two' from case '2' because ++$a > 2 increases $a but doesn't match $a.
default is a fallback and its position doesn't matter.
NB: the aforementioned switches are fugly and esoteric and are only provided as a proof-of-example.
Not the most readable use of, but yes you can.
Use if/else - if/elseif/else structure if you do need just a simple comparison.
This will not work, every case needs to be a scalar value. in your example case it is even worse, it may seem to work but...
$s < $v evaluates to false, which triggers on the $v because it is 0 in here.
http://php.net/manual/en/control-structures.elseif.php
if ($a > $b) {
echo "a is bigger than b";
} elseif ($a == $b) {
echo "a is equal to b";
} else {
echo "a is smaller than b";
}

php null value confusion in switch statement

I have the following php code that gives me an unexpected result:
$foo = NULL;
switch($foo)
{
case 0:
print "What?!";
}
I'd expect the result to be nothing, but it matches case 0. The php manual says that NULL is a non-value, so how can it equal 0?
The switch statement applies loose comparison which means that the following things are treated as equivalent to 0:
false
0
"0"
NULL
"any string"
""
beacuse php is not type strict language
$foo = NULL;
if( isset( $foo ) ) {
switch( $foo ) {
case 0:
print "WTF!!!";
}
}
This can be also written like
$foo = NULL;
switch( true )
{
case ( 0 === $foo ):
print "What?!";
default:
print "Default?!";
}
PHP is doing a type-coerced, weak comparison. You will need to do this instead:
$foo = NULL;
if ($foo === 0)
print "WTF!!!";
You can do what I did - it's lazy but it works.
Before running the switch, I checked if the value is null and, if so, changed it to something known:
IF ($foo==null) {
$foo == 99;
}
switch($foo)
{
case 99:
print "This is NULL"; break;
case 0:
print "What?!";
}
I'm assuming here, but it could be that the switch statement coerces the value of $foo when comparing to 0. To test this hypothesis, why don't you try adding this above the switch statement:
echo $foo == NULL;
This should echo 1 before the curse, if I'm correct...
EDIT: The inaccuracy is with my testing, and it was pointed out to me. Check the comments, if you are interested.
From what I've tested, the top answer is inaccurate.
It seems as though a PHP switch statement sees NULL as a "joker", and applies any case to it.
I tried with different numbers and with a string, and they all fired. Nothing there suggests it should be NULL, not even on PHP loose comparison.
So my suggestion is adding a case NULL: at the start, just as you add default at the end.
$foo = NULL;
switch($foo)
{
case NULL:
print "This is NULL"; break;
case 0:
print "What?!";
}
As of PHP 8, you can use the match expression:
The match expression branches evaluation based on an identity check of a value.
Similarly to a switch statement, a match expression has a subject expression that is compared against multiple alternatives.
Unlike switch, it will evaluate to a value much like ternary expressions. Unlike switch, the comparison is an identity check (===) rather than a weak equality check (==).
Match expressions are available as of PHP 8.0.0.
Per your example:
$foo = null;
$value = match($foo) {
0 => print('What?')
};
Will output:
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type null
So you can add a try/catch and handle it accordingly or add a default "catch-all":
$compare = null;
$value = match($compare) {
0 => print('What?'),
default => print('Default!')
};

Categories