PHP switch falling though issue - php

Code:
switch ($_GET['operation']) {
case "professionist":
case "company":
case "student":
echo "ok<br>";
case "professionist":
echo "inprofessionist<br>";
break;
case "company":
echo "incompany<br>";
break;
default:
echo "Meh!<br>";
break;
}
My goal is to execute some (common to professionist/company/student) code first, and then execute the rest of the code depending on the operation...
The problem is that the first 3 cases works perfectly, but then, if for example the operation is "company", the switch go on "professionist" case, what i'm doing wrong? How can improve that? Thanks in advance...

That's how switch works. If you always need to print "ok" then move it outside switch:
$op = $_GET["operation"];
if (in_array($op, array("professionist", "company"))) {
echo "ok<br>";
}
switch ($op) {
case "professionist":
echo "inprofessionist<br>";
break;
case "company":
echo "incompany<br>";
break;
default:
echo "Meh!<br>";
break;
}

Only the first case with a given value will ever be targeted by a switch. (And in fact, a switch only ever goes to a single case per execution - fallthough just lets you have multiple cases share some code, but only one of them is what's actually triggered.)
Thus, it doesn't make sense to have multiple casees with the same value that they're looking for - a switch statement isn't the same thing as a series of independent ifs; it's a mapping of jump targets.
Essentially, let's say you have a switch like this:
w; // 001
switch ($foo) { // 002
case 'a':
w; // 003
case 'b':
x; // 004
break; // 005
case 'c':
y; // 006
}
z; // 007
What actually winds up effectively happening is that you get some code effectively like this (note: highly simplified from how this actually works):
001 v
002 jump based on $foo: [a -> 003, b -> 004, c -> 006]
003 w
004 x
005 jump to 007
006 y
007 z
and then that program just gets run from top to bottom.
In the case where $foo is 'a', it jumps to 003 and runs from there, which means that it winds up doing v,jump,w,x,z in total.
In the case where $foo is 'b', it jumps to 004 and runs from there, which means that it winds up doing v,jump,x,z in total.
In the case where $foo is 'c', it jumps to 006 and runs from there, which means that it winds up doing v,jump,y,z in total.

Related

Switch too often triggered

I cannot get my head around this. There might be a simple solution and the problem addressed already, but I could not find an answer.
<?php
$string = '';
$array = array(1, 2, 3);
foreach($array as $number) {
switch($number) {
case '1':
$string .= 'I ';
case '2':
$string .= 'love ';
case '3':
$string .= 'you';
}
}
echo $string;
?>
As you might have guessed, the sentence produced should be: I love you
But that is the actual output: I love youlove youyou
How is this even possible, when the switch is only triggered thrice.
Meanwhile I know that the problem can be fixed with a >break;< after each case. But I still do not understand why this is necessary.
I would be very happy, if someone could explain to me what PHP is doing.
Happy Valentines!
When case 1 is matched it will also execute case 2 and 3 unless there is a break.
So each time through the loop the matched case and everything following is executed.
First time: case 1, 2, 3
Second time: case 2, 3
Third time: case 3
For reference, here's an extract from the PHP documentation on switch, which explains it better than I probably would. :)
It is important to understand how the switch statement is executed in order to avoid mistakes. 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. If you don't write a break statement at the end of a case's statement list, PHP will go on executing the statements of the following case. For example:
<?php
switch ($i) {
case 0:
echo "i equals 0";
case 1:
echo "i equals 1";
case 2:
echo "i equals 2";
}
?>
Here, if $i is equal to 0, PHP would execute all of the echo statements! If $i is equal to 1, PHP would execute the last two echo statements. You would get the expected behavior ('i equals 2' would be displayed) only if $i is equal to 2. Thus, it is important not to forget break statements (even though you may want to avoid supplying them on purpose under certain circumstances).
When you don't specify a break the code execution will fall-through to the next case.
As an example an exam paper with a score out of 10 could be graded as such:
switch ($score)
{
case 10:
// A+ when score is 10
echo 'A+';
break;
case 9:
case 8:
// A when score is 8 or 9
echo 'A';
break;
case 7:
case 6:
// B when score is 7 or 6
echo 'B';
break;
case 5:
case 4:
case 3:
// C when score between 3 and 5
echo 'C';
break;
default:
// Failed if score is less than 3
echo 'Failed';
}

Switch Case always falls through to default

It appears there's something wrong in my Switch Case logic as it always falls through to default.
echo $platform;
switch($platform){
case "Gaming / Xbox 360 Games":
$internalPlatform = "MXT";
break;
case "Gaming / Nintendo DS Games":
$internalPlatform = "NDS";
break;
default:
$internalPlatform = "MISC";
break;
}
echo $internalPlatform;
Where $platform = "Gaming / Xbox 360 Games" and $internalPlatform = "MISC".
Any ideas on what is causing it to fall through?
Nothing wrong with the logic above.
Thanks to Paolo for pointing out to strip tags & invisibles out the variable. var_dump helped me find that out!
Mybe you missed a prefix or suffix space
Try to comper the output of this echo with the case string.
echo "$platform";

Loop not writing correct values

I have a table that contains all the employees in a company (hr_employees). In addition to this table, is another table that has all their start dates and end dates, plus which type of contract they have (hr_employees_status).
With the data I get, I write a 1 or a 0 (1 permanent based, 0 other) to an excel spreadsheet, colour coded as determined by the type of contract (1 = black, 0 = blue, green, grey or red), in each month (from May 2005 up to present). How I determine what should go in which cell is by a case clause, looking at the current status in the hr_employee_status table.
It loops fine, and does 99% of what it should correctly. The only issue is that, as soon as an employee moves over from a temporary contract to a permanent basis, it sometimes doesn't write the correct value to a cell.
I have changed the code a bit to only pull month and year from the database (and set the day to 01), out of hopes that, since the month and year is all that is needed to write to a cell, it would write the correct data in the correct cell. But to no avail.
I don't know what code to post, so here is the loop that determines the type of contract and writes it to the excel sheet:
switch ($dates['status']) {
case '0':
$color = 'blue';
$cellcontent="0";
break;
case '1':
$color = 23;
$cellcontent="0";
break;
case '2':
$color = 'black';
$cellcontent="1";
break;
case '3':
$color = 'green';
$cellcontent="0";
break;
case '4':
$color = 'red';
if(mysql_num_rows($query) > 2)
$cellcontent = "0";
else {
$cellcontent="1";
}
break;
}
if($s['state'] == '4')
$color = 'red';
$format_content =& $workbook->addFormat(array('align' => 'center', 'size' => 11, 'numformat' => '#', 'fontfamily' => 'Calibri', 'left' => 1, 'bottom' => 1, 'right' => 1, 'color' => $color));
for($f = $start_at; $f <= $start_at+$count; $f++) {
$totalmonths = $totalmonths + $cellcontent;
$worksheet->write($k,15+$f,$cellcontent,$format_content);
}
$date is the results as received from the DB.
$start_at is the date the employee started with a contract type (and thus determines which month to mark).
$count is the difference between the start date, and the end date (amount of months).
I would like to know WHY does it not start at the correct date when switching form a temporary contract, to a permanent one.
If any other info is required, please let me know.
EDIT 1: - Response to feedback from DaveRandom and Oleg
#DaveRandom:
hr_employees looks like this:
------------------------------------------
|employee_id|name|surname|otherinfo|state|
|1 |Foo |Bar | ******* | 1 |
|2 |Ben |Smith | ******* | 1 |
------------------------------------------
hr_employees_status looks like this:
------------------------------------------
|employee_id|from_date |to_date |status|
|1 |2006-07-12|2009-08-11| 0 |
|1 |2009-08-12|0000-00-00| 1 |
|2 |2009-07-01|0000-00-00| 1 |
------------------------------------------
And then the excel sheet will output
Name Surname Start Date *dates* June-06 July06 ->- July09 Aug09 Sep09
Foo Bar 2006-07-12 *empty* 0 ->- 0 1 1
Ben Smith 2009-07-01 *empty* *empty* ->- 1 1 1
#Oleg
$start_at is as follows:
round(((substr($dates['from_date'],0,4) * 12) + substr($dates['from_date'],5,2)) - ((substr($start_date,0,4) * 12) + substr($start_date,5,2))) + 1;
// $dates is a loop through the hr_employee_status table
See above. $dates is a loop through the hr_employee_status table. I'm 100% sure that status is in there.
Please explain type juggling? All the values in status is varchar (and don't ask me why, looking at it now, it seems like a stupid thing to do...)
We are missing some crucial part of your code, so until you provide more details (could you show us where you define $start_at for example?) I can only guess...
You ask "why does it not start at the correct date" but you never provide the code where $start_at is defined. It could be useful to us.
Why are you switching $dates['status']? Are you sure it's in $dates?
The switch statement compares values after type juggling...
Example from php.net:
switch ("a") {
case 0:
echo "0";
break;
case "a": // never reached because "a" is already matched with 0
echo "a";
break;
}
This might be your case where the permanent contract status 1 is never reached in your switch statement because of incorrect type of $dates['status'] making it stop at case '0':.
Try using var_dump() to see the exact types and values of variables you're operating on in your code.

Conditional switch statements in PHP

I'm quite used to vb.net's Select Case syntax which is essentially a switch statement, where you can do things like Case Is > 5 and if it matches, it will execute that case.
How can I do what I'm going to call "conditional switch statements" since I don't know the actual name, in PHP?
Or, what's a quick way to manage this?
switch($test)
{
case < 0.1:
// do stuff
break;
}
That's what I've tried currently.
I think you're searching for something like this (this is not exactly what you want or at least what I understand is your need).
switch (true) finds the cases which evaluate to a truthy value, and execute the code within until the first break; it encounters.
<?php
switch (true) {
case ($totaltime <= 1):
echo "That was fast!";
break;
case ($totaltime <= 5):
echo "Not fast!";
break;
case ($totaltime <= 10):
echo "That's slooooow";
break;
}
?>
I tried to add this as a comment to the answer by BoltCock, but SO is telling me that his answer is locked so I'll make this a separate (and essentially redundant) answer:
The "switch(true)" answer from BoltCock is much like the following example, which although logically equivalent to if + else if + else is arguably more beautiful because the conditional expressions are vertically aligned, and is standard/accepted practice in PHP.
But the if + else if + else syntax is essentially universal across scripting languages and therefore immediately readable (and maintainable) by anyone, which gives it my nod as well.
There is an additional way you can accomplish this, in PHP 8.0+, by using a match statement.
If you have a single expression within each case, it is equivalent to the following match statement. Note that unlike switch statements, we can choose to return a variable (in this code I am storing the result in $result).
$test = 0.05;
$result = match (true) {
$test < 0.1 => "I'm less than 0.1",
$test < 0.01 => "I'm less than 0.01",
default => "default",
};
var_dump($result);
Match statements only allow you to have a single expression after each condition. You can work around this limitation by calling a function.
function tinyCase(){}
function veryTinyCase(){}
function defaultCase(){}
$test = 0.01;
match (true) {
$test < 0.1 => tinyCase(),
$test < 0.01 => veryTinyCase(),
default => defaultCase(),
};
And for reference, if you just want to check for equality you can do:
$result = match ($test) { // This example shows doing something other than match(true)
0.1 => "I'm equal to 0.1",
0.01 => "I'm equal to 0.01",
default => "default",
};
Match statements do have some key differences from switch statements that you need to watch out for:
My last example will use a strict equality check === instead of a loose one ==.
If a default case is not provided, an UnhandledMatchError error is thrown when nothing matches.
And there is no worrying about falling through to the next case if you forget to add break.
PHP supports switch statements. Is that what you wanted?
Switch statement with conditions
switch(true)
{
case ($car == "Audi" || $car == "Mercedes"):
echo "German cars are amazing";
break;
case ($car == "Jaguar"):
echo "Jaguar is the best";
break;
default:
echo "$car is Ok";
}

Can I use a logical "or" in a PHP switch statement case?

Is it possible to use "or" or "and" in a switch case? Here's what I'm after:
case 4 || 5:
echo "Hilo";
break;
No, but you can do this:
case 4:
case 5:
echo "Hilo";
break;
See the PHP manual.
EDIT: About the AND case: switch only checks one variable, so this won't work, in this case you can do this:
switch ($a) {
case 4:
if ($b == 5) {
echo "Hilo";
}
break;
// Other cases here
}
The way you achieve this effectively is :
CASE 4 :
CASE 5 :
echo "Hilo";
break;
It's called a switch statement with fall through. From Wikipedia :
"In C and similarly-constructed languages, the lack of break keywords to cause fall through of program execution from one block to the next is used extensively. For example, if n=2, the fourth case statement will produce a match to the control variable. The next line outputs "n is an even number.". Execution continues through the next 3 case statements and to the next line, which outputs "n is a prime number.". The break line after this causes the switch statement to conclude. If the user types in more than one digit, the default block is executed, producing an error message."
No, I believe that will evaluate as (4 || 5) which is always true, but you could say:
case 4:
case 5:
// do something
break;
you could just stack the cases:
switch($something) {
case 4:
case 5:
//do something
break;
}
switch($a) {
case 4 || 5:
echo 'working';
break;
}

Categories