strange beahviour with a php switch? - php

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

Related

Use OR within if else condition by inverse condition order in php

I am trying to get "OK" if my condition False, i want to keep same if else order as given example, don't advice to move "else" content in "if" and "if" content in "else",
<?php
//Case 1 Both False
//$point = 1001; //more than 100
//$flag = 1; //flag is = 0
//Case 2 First False Second True
//$point = 1000; //less than 1000
//$flag = 0; //flag is = 0
//Case 3 First TRUE Second FALSE
//$point = 100; //less than 100
//$flag = 1; //flag is = 1
$point = 1001;
$flag = 1;
?>
<div class="box border">
<div class="box-title">
<?php if($flag == 0 || $point < 1000) { ?>
<h4>Not OK</h4>
<?php } else { ?>
<h4>OK</h4>
<?php }?>
</div>
in above script
//Case 1 is working
but
Case 2 and Case 3 both not working with OR operator
I want all 3 cases work in same pattern
After reading your comments:
It seems you want to show some score (in the else-branch of an if-then-else) if the user has equal/more than 1000 points or you toggle a flag (which basically means "always show points").
Normally you'd be doing that in the if-branch:
if ($flag || $point >= 1000)
{
echo "OK";
} else {
echo "Not OK";
}
Since you want the Not OK to be in the if-Branch you need to inverse the condition, doing so means inverting every part of the condition and the operators aswell:
$flag becomes !$flag
$point >= 1000 becomes $point < 1000
|| becomes &&
Result:
if (!$flag && $point < 1000)
{
echo "Not OK";
} else {
echo "OK";
}
Writing this into a truth-table:
flag point result
0 < 1000 Not OK
1 < 1000 OK
0 >=1000 OK
1 >=1000 OK
I tested this code and it works.
if(!($flag != 0 || $point >= 1000)){
echo "Not OK";
}else{
echo "OK";
}

Switch doesn't work with numeric comparison cases

Here is my code.
$value = 0;
switch($value) {
case ( $value <= 25 ):
$CompScore = 'low';
break;
case ($value > 25 && $value <= 50 ):
$CompScore = 'fair';
break;
case ($value > 50 && $value <= 75 ):
$CompScore = 'good';
break;
case ($value >75 ):
$CompScore = 'excellent';
break;
default:
$CompScore = 'low';
break;
}
echo $CompScore;
When the value is 0, $compScore is fair. Why it is not showing low? I don't understand why.
switch not working like that.
Since $value is 0 which is falsy value.
$value <= 25 is true, $value > 25 && $value <= 50 is false, so $CompScore will be 'fair'.
For you code, use an if elseif else flow will be more readable.
You could rewrite your code like below:
// from excellent to low
if ($value > 75) {
$CompScore = 'excellent';
} else if ($value > 50) {
$CompScore = 'good';
} else if ($value > 25) {
$CompScore = 'fair';
} else {
$CompScore = 'low';
}
The problem is, you use your switch in a particular way.
You are saying :
$value = 0;
Switch ($value){
case ($value < 25):
....
}
This finally compares $value<25 and 0 as described below :
($value<25) == $value.
=> true == 0
Which is wrong because true != 0
A way to do what you want this way is simply to replace switch($value) with switch(true) so the interpreter will actually compare check if your case statements are true.
The value you pass into a switch statement is basically what the switch statement looks for an evaluated match for, going from top to bottom down the list of cases until it finds one it is equal to (loose comparison), e.g. true == true.
In your example, your comparisons are evaluated as booleans (true or false) - your variable $value is set to zero, which is equal to false, but not identical (strict comparison) to false. For example:
(0 == false) // true
(0 === false) // false
(1 == false) // false
(1 === false) // false
(1 == true) // true
(1 === true) // false
(true === true) // true
So by using a boolean true as your switch value, you can do this to have numeric comparison inside the statement, where each comparison will evaluate to either true or false to match/not match the original true value (boolean - boolean comparison).
switch(true) {
case ($value <= 25): // true
$CompScore = 'low';
break;
case ($value > 25 && $value <= 50 ): // false
$CompScore = 'fair';
break;
case ($value > 50 && $value <= 75 ): // false
$CompScore = 'good';
break;
case ($value >75 ): // false
$CompScore = 'excellent';
break;
default: // if you removed the first case
$CompScore = 'low'; // this default case would be used
break;
}
You can "smarten up" your code with a lookup array and some simple mathematics.
Code: (Demo)
$lookup = [
1 => 'low',
2 => 'fair',
3 => 'good',
4 => 'excellent'
];
for ($i = -1; $i <= 101; ++$i) {
echo "\n$i : " , $lookup[ceil($i / 25)] ?? $lookup[1];
}
By dividing the value by 25, then rounding up to the next whole number (with ceil()), you achieve the same result without a battery of condition statements. Using a lookup away not only keeps your code compact, it ensures that you aren't performing n checks on the same value AND it provides a clean separation between the process and the values.
If you ever decide to split the groups by 20, instead of 25, you would only need to change the 25 to 20, then add a fifth lookup value in the desired location (with the appropriate key).

Switch evaluations

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)

Switch function in PHP

What do I have to write in the cases (of switch function in PHP) to make if $number > 0 && $number < 15?
I tried with:
<?php
$number = rand("0","100");
switch($number) {
case: $number > 0 && $number < 15;
$output = 1;
break;
case: $number > 15 && $number < 50;
$output = 2;
break;
}
return $output;
?>
Try the following. Your colons were in the wrong place!
<?php
$number = rand("0", "100");
switch(true) {
case $number > 0 && $number < 15:
$output = 1;
break;
case $number > 15 && $number < 50:
$output = 2;
break;
}
?>
From the comment by DaveRandom below. Be aware that nothing will happen if $number is equal to 15. I would recommend changing one of your switch statements. Perhaps by changing your first case into:
case $number > 0 && $number <= 15:

Case statement is not outputting correctly?

This is very strange but below is my case statement:
switch($grade){
case ($average >70):
$grade = 'A';
break;
case ($average >=60 && $average <=69):
$grade = 'B';
break;
case ($average >=50 && $average <=59):
$grade = 'C';
break;
};
So if its 70+ it is grade A, 60-69 grade B, 50-59 grade C.
But instead it outputting this: 60+ grade A, 50-59 grade B, 40-49 grade C.
Why is it doing this because function seems correct?
echo "<p><strong>Average Mark:</strong> $average</p>";
echo "<p><strong>Average Grade:</strong> $grade</p>";
As others mentioned in comments, the "condition" in a case should be a static value, not a logical expression.
Also, the value you're switching on (in your case, $grade) should is the one you're testing. You appear to be using it as a hint about what variable you're assigning.
The simplest way to fix your code would be to use an if-elseif-else construct:
if ($average >70)
$grade = 'A';
elseif ($average >=60 && $average <=69)
$grade = 'B';
elseif ($average >=50 && $average <=59)
$grade = 'C';
However, to be perverse, and to illustrate how a switch statement works, you could also do the following:
switch(true){
case ($average >70):
$grade = 'A';
break;
case ($average >=60 && $average <=69):
$grade = 'B';
break;
case ($average >=50 && $average <=59):
$grade = 'C';
break;
};
In this example I'm comparing the value true to each of the cases in turn, where each of those case-values is actually the result of evaluating a boolean expression. The first expression whose value matches true will fire.
Probably not much help, if you don't understand switch statements.
Edit: I just noticed that there's a gap in the logic: what if someone's average is exactly 70? Using a cascading statement like a switch or if-else, you can eliminate some of the redundant (and in this case damaging) code, thus:
if ($average >=70)
$grade = 'A';
elseif ($average >=60)
$grade = 'B';
elseif ($average >=50)
$grade = 'C';
// ...
else
$grade = 'F';
...and so on, to whatever lowest grade you're using.
For those of you saying switch the variable you $average, you are wrong. The only reason it is evaluating in that instance is because switch uses loose comparison, so it is saying that $average being set is true and comparing it to the conditionals, all of which will be either true or false. Previously, using $grade which was unset was evaluating the switch to false because in loose comparison, a variable which is unset will throw a notice and return false.
While I recommend using if-then-else, the proper answer for using a switch statement in this case is as follows:
switch (true) {
case ($average >= 70):
$grade = 'A';
break;
case ($average >= 60 && $average < 70):
$grade = 'B';
break;
case ($average >= 50 && $average < 60):
$grade = 'C';
break;
}
Like said above, every statement will return either true or false. The idea is that only one statement should ever return true at one time, thus the switch statement will match it's value of true to the one statement that passed and execute that code only, since all of the other ones are false and didn't match.
You should use if/else - statements:
if($average >70)
{
$grade = 'A';
} else if($average >=60 && $average <=69)
{
$grade = 'B';
} else if($average >=50 && $average <=59)
{
$grade = 'C';
}
Edit: Alternatively you can calculate the $grade value (50-100 in this example):
$grades = "CBAAA";
$grade = $grades[(int)($average/10) - 5];
The switch loop compares the cases. If you really want to use switch for the job (and not if / elseif / else), then you can to it with a switch that compares against TRUE:
switch(TRUE)
{
case $average > 70:
$grade = 'A';
break;
case $average >= 60 && $average <= 69:
$grade = 'B';
break;
case $average >= 50 && $average <= 59:
$grade = 'C';
break;
default:
throw new Exception(sprintf('Unable to map average (%d) to a grade.', $average));
}

Categories