PHP switch case - flawed or valid? [duplicate] - php

This question already has answers here:
Why was the switch statement designed to need a break?
(9 answers)
Closed 8 years ago.
I don't understand why a switch-case statement requires you to explicitly insert a break after each case. Isn't the whole point of it to stop once a case is made?
Can someone give me a circumstance where a case is found true but for some reason [you insert reason here] you still need the code block to execute through.
This is a vaild PHP switch-case statement
switch ($error) {
case 'empty':
$msg = 'Field cannot be empty.';
break;
case 'invalid':
$msg = "Field may only contain number.";
break;
}
This is a invaild PHP switch-case statement
switch ($error) {
case 'empty':
$msg = 'Field cannot be empty.';
case 'invalid':
$msg = "Field may only contain number.";
}
So is this break useless or does it serve a purpose in some situations?

Because that's just how it works - it's how the language was designed. Probably because that's how C did it.
The most common use is for two cases to be treated the same.
switch ($error) {
// Treat warnings and errors the same
case 'warning':
case 'error':
echo "Something went wrong.";
break;
}

I believe this question is a duplicate to this one, answered robustly by #Micahel Burr :
Many answers seem to focus on the ability to fall through as the reason for requiring the break statement.
I believe it was simply a mistake, due largely because when C was
designed there was not nearly as much experience with how these
constructs would be used.
Peter Van der Linden makes the case in his book "Expert C
Programming":
We analyzed the Sun C compiler sources to see how often the default
fall through was used. The Sun ANSI C compiler front end has 244
switch statements, each of which has an average of seven cases. Fall
through occurs in just 3% of all these cases.
In other words, the normal switch behavior is wrong 97% of the time.
It's not just in a compiler - on the contrary, where fall through was
used in this analysis it was often for situations that occur more
frequently in a compiler than in other software, for instance, when
compiling operators that can have either one or two operands:
switch (operator->num_of_operands) {
case 2: process_operand( operator->operand_2);
/* FALLTHRU */
case 1: process_operand( operator->operand_1);
break; }
Case fall through is so widely recognized as a defect that there's
even a special comment convention, shown above, that
tells lint "this is really one of those 3% of cases where fall through
was desired."
I think it was a good idea for C# to require an explicit jump
statement at the end of each case block (while still allowing multiple
case labels to be stacked - as long as there's only a single block of
statements). In C# you can still have one case fall through to another
- you just have to make the fall thru explicit by jumping to the next case using a goto.
It's too bad Java didn't take the opportunity to break from the C
semantics.

It's also used for combinatory conditions.
To give a somewhat useless example:
// manually total up a number by 1
$sum = 0;
switch ($number) {
case 4:
$sum += 1;
case 3:
$sum += 1;
case 2:
$sum += 1;
case 1:
$sum += 1;
}
This sets switch apart from exclusive if trees in that one case can be a superset of another, and reduces code duplication. If all your cases contain a break, then you can certainly transpose it into an if list. (switch is often just utilized for stylistic reasons).

A single statement can carry multiple case labels, as the following example shows where we are not using break:
switch($constant)
{
case 'a' :
case 'b' :
case 'c' :
case 'd' :
case 'e' :
case 'f' : hexcvt(c);
}
In this example, if constant-expression equals any letter between 'a' and 'f', the hexcvt function is called.

Related

Should default case always be the last in switch statement? [duplicate]

I've tested this and it works fine, but it looks... weird... to me. Should I be concerned that this is nonstandard form which will be dropped in a future version of PHP, or that it may stop working? I've always had a default case as the final case, never as the first case...
switch($kind)
{
default:
// The kind wasn't valid, set it to the default
$kind = 'kind1';
// and fall through:
case 'kind1':
// Do some stuff for kind 1 here
break;
case 'kind2':
// do some stuff for kind2 here
break;
// [...]
case 'kindn':
// do some stuff for kindn here
break;
}
// some more stuff that uses $kind here...
(In case it's not obvious what I'm trying to do is ensure $kind is valid, hence the default: case. But the switch also performs some operations, and then $kind is used after the switch as well. That's why default: falls through to the first case, and also sets $kind)
Suggestions? Is this normal/valid syntax?
It is an unusual idiom, it causes a little pause when you're reading it, a moment of "huh?". It works, but most people would probably expect to find the default case at the end:
switch($kind)
{
case 'kind2':
// do some stuff for kind2 here
break;
// [...]
case 'kindn':
// do some stuff for kindn here
break;
case 'kind1':
default:
// Assume kind1
$kind = 'kind1';
break;
}
In case anybody find this page through google as I did:
I was wondering the same thing as Josh - so...
One thing is standards, which I think we should all try harder to adhere too, but another thing is hacking (in the: exploit-every-possibility kinda way).
While it's ugly/weird/not normal - it IS possible and IMHO could be useful in some rare cases...
Consider the following:
$color = "greenish";
//$color = "green";
switch($color) {
default:
echo "no colors were selected so the color is: ";
case "red":
echo "red<br />\n";
break;
case "blue":
echo "blue<br />\n";
break;
case "green":
echo "green<br />\n";
break;
}
If $color = "greenish"; the code will print
no colors were selected so the color is red
while if $color = "green"; or any other defined cases, it will just print the color.
It know it not the best example, but you get the point ;)
Hope it helps somebody.
It looks odd for the same reason that
else {
echo "lol";
}
if (1 == 1) {
echo "bbq";
}
would look odd, if it were valid. If for this reason alone I'd avoid it.
In addition, you know that every time you show the code to somebody, you're going to have to explain that putting the default case first was deliberate; this is usually a sign that it's not a great idea.
This is how I'd probably do it... it's easy on the eye and keeps the functionality.
switch($kind)
{
default :
case 'kind1':
$kind = "kind1";
// Do stuff for kind 1
break;
case 'kind2':
// do stuff for kind2
break;
case 'kindn':
// do stuff for kindn
break;
}
I'd personally prefer to do
switch($kind)
{
case 'kind2':
// do some stuff for kind2 here
break;
// [...]
case 'kindn':
// do some stuff for kindn here
break;
case 'kind1':
default:
$kind = 'kind1'; // Redundant if it's already set as 'kind1', but that doesn't make any difference to the code.
// Do some stuff for kind 1 here
break;
}
This can be really handy for flow control, particularly if you aren't breaking between cases.
For example:
$step = $_GET['skip_to_step'];
switch($step) {
default:
case 'step1':
// do some stuff for step one
case 'step2':
// this follows on from step 1 or you can skip straight to it
}
You could add in an additional 'if', or a clever 'or' to make $step default to 'step1' before you start the switch but that's just extra code, reducing readability.
Common practice is to define the default option as last option. But I see nothing wrong with your solution (if there is no predefined schema in your company how to layout your code)
Kind of made me twinge at first, but that's just because we're not use to seeing things that way.
I would suggest that you document this highly, since some might call this "tricky" code. A noob or some future maintainer might come along and move it to the bottom where they're more comfortable with it and break the side-effect that is has being at the top.
Other answers give good examples of it, just stating for clarity's sake...
A Case (including default) does not stop executing at its end unless you include a break. Although switch is often compared to a sequence of if elseif elseif etc., however it's not quite that.
Short version: SWITCH/CASE only acts like IF/ELSEIF/ELSE if you include breaks after each case. SWITCH/CASE is more like a series of "if" statements where each has the same variable check with a different value it's being checked against.
Long version: Without including a break, each case is a "start here"and the differences in a lot of ways make it closer to GOTO without the drawbacks. Technically, if you really REALLY wanted to (read, were a masochistic coder who wanted to really challenge themselves) you could write almost any procedural programs using only one external array, a for loop, and a switch nested inside.
Seriously, why you would want to do this boggles my mind, but it really demonstrates how far switch/case can deviate from if/elseif patterns, so it's here for you for academic reasons (but don't do it!)...
$array = [];
$array['masterLoop'] = 1;
$for ($i = 0, $i < $array['masterLoop'], $i++ ){
switch($array['goto']){
default:
case 1:
PRINT: "Welcome to the program";
case 2:
PRINT: "Please make a choice:";
case 3:
$array['choice']='';
// Wait for some input variable and set choice to it.
case 4:
$array['goto']=$array['choice'];
$array['masterLoop']++;
}
}
The way this code would run (after you set up something for capturing and setting a choice) would be it'd start up with
"Welcome to the program. Please make a choice."
<<user inputs 2>>
"Please make a choice."
<<user inputs 1>>
"Welcome to the program. Please make a choice."
<<user inputs 3>>
// program awaits user input
<<user inputs 4>>
// user triggers infinite loop
So... you can use switches to reflect back to the days of BASIC...
but if you do and I have to debug your code later after you wrote it all like that...
May Linus Torvalds mercy on your soul.

Repeating code in switch statements

I've got and switch statements like this:
switch(x){
case a:
executeSth();
executeA();
break;
case b:
executeSth();
executeB();
break;
...
}
so executeSth(); should allways be executed except in default case but after it some case specific code is called (executeA(); or executeB() and so on). (So simply putting it in front of the switch doesn't work).
Is there an efficient way to reduce the number of "executeSth();" without sacrificing performance?
I could only imagine split it into two switches (one that executes the executeSth() in and one that executes the specific code) but that would sacrifice performance. Maybe you got better ideas?
I'm basicly interessed in code for c/c++ or php. My goal is to minimize code size and in case of c/c++ the size of the resulting executable.
Edit: Yes, the order of the functions matters.
Edit2: I don't have the choice between php or c++, I need it both to be as good as possible.
A nested switch is an option...
This uses two switches, but the second is not triggered in the default case so has a slightly better performance profile than just two in-line switches.
switch($x) {
case a: case b: case c:
executeSth();
switch($x) {
case a:
executeA();
break;
case b:
executeB();
break;
case c:
executeC();
break;
}
break;
default:
...
}
Alternatively, a variable function may do the job...
This is a PHP option which may work, though a lot of people don't like variable functions. This is probably the best option if you want to totally remove nesting & repetition.
switch($x) {
case a:
$function = "executeA";
break;
case b:
$function = "executeB";
break;
case c:
$function = "executeC";
break;
default:
...
}
if(isset($function)) {
executeSth();
$function();
}
I've also made a little live test bed here, if anyone wants to test their PHP solutions work before posting them (case 10 should executeSth() and executeA(), case 20 should executeSth() and executeB(), default should executeDefault()).
In C++, you can use a function pointer to achieve the same as the above
I had a total brain fart when I wrote this, thankfully idipous reminded me that we can do this with a simple function pointer.
// Declare function pointer
int (*functionCall)() = NULL;
// In switch statement, assign something to it
functionCall = &execute;
// After the switch statement, call it
int result = (*functionCall)();
Note: I'm out so haven't checked the syntax on these. The syntax I've used is C syntax and may require some small changes to work in C++.
What you could do (although it might not be the most readable solution) and that if you are using PHP 5.3 and above you could create a method like below:
function mymethod($funcToCall){
executeSth();
$funcToCall();
}
and have the swtich like below:
switch(x){
case a:
mymethod('executeA');
break;
case b:
mymethod('executeB');
break;
...
}
Unless there is really a huge amount of this sort of thing, I'd leave it as is.
One solution is of course to move the call of executeSth into the executeA defintion and executeB definitions - this is of course only meaningful if there are multiple places with similar code - if there aren't more than one place, you have moved two lines of code from one place to another place.
Another solution may be to pass the function executeA or executeB into executeSth as an argument. But it will just make things more complicated to read.
In general, I'd say "smaller code" is not necessarily "better code". The key is to make the code as clear as possible (whilst still achieving reasonable performance and code-size, of course).
In C++, I would additionally expect that if executeSth is small, that it gets inlined into the case-code. So there is no overhead difference between having one or two function calls.
Why don't you set a flag in your default case, and then, after the switch statement, execute the common function if the flag is not set (meaning that it's not the default case)? That sounds like a reasonable solution.
$flag = false;
switch(x){
case a:
executeA();
break;
case b:
executeB();
break;
default:
... // other stuff
$flag = true;
break;
}
if ( !$flag )
executeSth();
EDIT
I misinterpreted the question.
For the reverse order you can put the possible cases in a variable and then use something like in_array in PHP or strstr in C++ (not sure if there's a better native function):
if ( !in_array(x, cases) {
executeSth();
}
switch(x){
case a:
executeA();
break;
case b:
executeB();
break;
...
}
In code size speaking: it doesn't matter. Readability > codesize.
Perhaps you can write something like that for your executeSth():
if(!notDefault){
executeSth();
}
(C++) Let the preprocessor duplicate the code for you? (Dᴏɴ’ᴛ Uꜱᴇ Tʜɪꜱ ɪɴ Mᴀɪɴᴛᴀɪɴᴇᴅ Cᴏᴅᴇʙᴀꜱᴇ. It may hurt readability. I think the two-switch solution is fine.)
#define CASE(n) case n: printf("non-default\n"); _unused_label_##n
switch (x) {
CASE(1):
printf("case 1\n");
break;
CASE(2):
printf("case 2\n");
break;
default:
printf("case else\n");
break;
}
#undef CASE

Loops within Switch statement

my switch statement has about ten outcome, but some of them need 1/2 loops to check, so i can't write them within case(condition), so i've tried using more than one default case, is this possible?
<?php
switch(true) {
case 1:
break;
case 2:
break;
default:
echo "this text is never printed ??";
while(true) {
while(true) { // case 3
break 3;
}
break;
}
while(true) {
// case 4
break 2;
}
case 5:
break;
default:
while(true) {
// case 6
break 2;
}
case 7:
break;
}
?>
is this sort of thing possible, as my first default doesn't seem to be executing at all?!
thanks
You cannot have more than one default in a switch statement. Also, default should be at the end of of the switch after all the case statements.
What might be happening when your code is run through the PHP engine is that the parser is reading the switch statements into a hash map type data structure and each time the parser finds a default label, it's overwriting the existing entry in the hash map. So only last default label ends up in the data structure that gets used in execution.
No this isn't possible, you can't have more than one default case in a switch statement, you'll need to put additional logic into the single final case statement.
when the default case is reached it captures all conditions so later cases are not evaluated.
To answer your question - no, it is only possible to have one default and that at the end. I'm not sure whether you can place other cases after the default, but what I'm sure of is that they would never be reached...
EDIT:
Also, I don't see what you're trying to do there. What's the point? Could you explain a bit? We might be able to help you accomplish what you want to do
You can have only one default in a switch. Remember that Zend is not the only thing that parses PHP, you may confuse other parsers by not putting the default case as the very last part of the switch.

PHP Coding styles return; in switch/case

we're trying to implement new coding style guidelines for our team, the php codesniffer is printing an warning on switch case statements when no "break" is found like:
switch ($foo) {
case 1:
return 1;
case 2:
return 2;
default:
return 3;
}
is there any good reason to use :
switch ($foo) {
case 1:
return 1;
break;
}
?? the break is never reached ?
It's perfectly valid to leave out the break when you return from a switch.
But it's fairly common practise to add explicit breaks to every case as a defensive programming practise.
switch ($foo) {
case 1:
return 1;
break;
case 2:
return 2;
break;
}
The idea is that should you later change your code in case 1 and remove the return statement, you could forget to add a break.
That would accidentally cause program flow to fall through to case 2.
switch ($foo) {
case 1:
somethingDifferent();
case 2:
return 2;
break;
}
Falling through case statements is slightly unusual and you should add a comment to your code when you do it to show that it's intentional.
switch ($foo) {
case 1:
somethingDifferentAndWeWantToDoCase2AsWell();
// fallthrough
case 2:
return 2;
break;
}
As with many defensive programming practises you've got to balance whether the code bloat - which potentially clutters your code and make it less readable - is worth it or not.
If your "php codesniffer is printing a warning" try to get another better codesniffer and don't forget to try to use the last PHP stable version. You can, of course, write a breakafter one return, but it doesn't make sense, because it will never be read at all. Your code is OK.
Look at this:
$fun = function(int $argument): string {
switch ($argument) {
case 1:
return "one";
case 2:
return "two";
default:
return "more than two";
}
};
$str = $fun(4); // return "more than two"
In my opinion, this is simpler and better: fewer lines => less code to maintain :-)
To answer your question, no there's no good reason to have something that does nothing. Think about it this way, a comment after the return instead of a break saying "don't forget" will have the same affect - none. And put that way it sounds silly, right?
Unless you need to set a var to use later, I'd suggest the approach you have is perfectly fine. I knew the code's intent within 2 seconds from looking at it. Having a break just creates confusion.
There is no one size fits all really. The correct approach depends on whichever fits the scenario. Set a variable in each case and having a break may be the right way, or perhaps just return makes sense.
Some observations on other suggestions made in answers:
1) Not having a break after return means problems could arise if code is later changed
Whenever possible, code should be explicit, as well as readable and clear. We can also code in a way to make future changes easier. But in something as simple as a switch it should be no problem and need no safety net to refactor a case later to add or remove a return or break.
In fact, if you removed a return and "didn't notice there was no break" then that's a poor mistake and could be made in any part of coding. No gotcha checking will save you from that. And one should be very careful coding for future potentials, as that potential may never happen, or something else may happen, and you just end up maintaining obsolete code for years.
In the same vein this was argued to be a safety net for future changes - What if you remove the return and accidentally left in that safety net break when you should have removed it?
Even if this switch statement was a life or death scenario, really serious code, I would be against adding the "pointless" break after the return. Just make sure whoever was working on the code knew what they were doing, and it was code reviewed by enough eyes and tested fully.
If it was that serious, then you'd have additional checks in place better than a proposed safety net to catch sloppy devs.
To argue that break after return adds a safety net, means you're not coding or testing properly. If this is a safety net deemed useful then it's likely there are tons of bugs in the code in potentially more serious places.
The wiki article of "Defensive Programming" was linked to, but it's not relevant here:
Defensive programming is a form of defensive design intended to ensure
the continuing function of a piece of software under unforeseen
circumstances.
Leaving a safety net break in is not a scenario of unforeseen circumstances, nor defensive programming. It's just bad coding, and you can't litter your code with back up code just in case you don't code correctly when you change something. That's such a bad approach to coding. The argument that "if someone removed return it won't work", well you could also have a typo in the case var, or forget to write the case, or...
The return returns, and you don't code "defensively" to avoid a return failing. That would mean PHP is broken, and you aint gonna fill your code with safety nets to cater for that. That's something you have on a much higher level up.
2) break after return keeps it explicit
But it's explicitly wrong. The return returns, so the break won't happen. To me that is scratch head time wondering if I've missed the intent - not for long as it's clear what will happen, but there will be a moment where I ponder it to make sure I've not missed something.
While it's not invalid or error to have a return and then break in the same case, it's just entirely pointless as the break does nothing. It's pointless code that needs to be seen, maintained, and figured out as it's not logical.
If explicit is the core goal and having a break after a return urks you because it's pointless, then I'd say it'd be better to set a variable and break, then return the variable after breaking from the switch.
Like #RageZ answer https://stackoverflow.com/a/1437476/2632129
3) Set a variable and return after the switch statement is completed
There's nothing wrong with this approach at all, but if there's no reason to store the value in a variable (later use etc) then it's good to return immediately when there's no need to hang around to do anything else.
That shows clear intent - return a value as soon as the case is matched.
I have much better solution.Please follow below code for above switch statment:
$result = 3; // for default case
switch ($foo) {
case 1:
$result = 1;
break;
case 2:
$result = 2;
break;
default:
// do nothing
}
return $result;
It will not result in any error and code is also fine with concepts.
I am not an expert in perfect coding but I think the validator would prefer something like that
switch ($foo) {
case 1:
$ret = 1;
break;
case 2:
$ret = 2;
break;
default:
$ret = 3
}
return $ret
I think using return in case statement to break the flow of the code is not really a best practice. So that's why the validator say there is no break ...
For your question about at category, I don't know ... sorry
From the PHP manual (http://us3.php.net/manual/en/control-structures.switch.php) :
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).

Does the order of cases matter in PHP switch statements?

In PHP switch statements, does placing more common cases near the top improve performance?
For example, say the following function is called 1,000 times:
<?php
function foo_user ($op) {
switch ($op) {
case 'after_update':
//Some Stuff
case 'login':
//Some other Stuff
}
}
If in 990 of the 1,000 of the times the function is called the $op argument is 'login', would performance improve by having case: 'login' above case 'after_update': in the switch statement? For example, would the code after case 'after_update': be ignored if $op = login was passed?
I've run some informal tests on this idea, but the difference has been negligible -- perhaps because the code after case: 'login' and case 'after_update': are both trivial. I'd prefer to avoid setting up a more extensive test with non-trivial operations if someone knows the answer outright.
This is specifically a Drupal question, but I imagine it could be addressed by anyone who is familiar with optimizing PHP.
This is likely going to be called a micro optimisation. I don't believe there would be a large difference.
However, order does mean a lot to the logic of the switch case if you allow the cases to fall through, example
switch ($var) {
case 0:
case 1:
do_it();
break;
case 2:
do_it_else();
break;
}
The order is important, the case will fall through and execute any code until it hits a break.
I wouldn't be concerned about the speed of the switch case, unless you had say 100 possible cases. But if then, it'd be likely you should refactor your code.
You will need a whole lot more than 1000 cases to notice a difference, but yes, there is a difference. I wrote up a test:
function test_switch($value) {
$startTime = time() + microtime();
for ($i = 0; $i < 10000000; $i++) {
switch($value) {
case "abcdefg":
$j = $j + 1;
break;
case "hijklmno":
$j = $j + 1;
break;
}
}
$endTime = time() + microtime();
echo "Total time for argument $value: " . ($endTime - $startTime) . "<br>\n";
}
test_switch("abcdefg");
test_switch("hijklmno");
That is 10 million executions of the switch statement. The output is:
Total time for argument abcdefg: 3.99799704552
Total time for argument hijklmno: 5.38317489624
So there is a difference, but it won't be noticeable until you reach on the order of 10 million executions, depending on your processor of course.
If you do not use break; to close each statement PHP will continue to evaluate cases until the end of the switch block which may impact performance in a large enough block. The order then becomes important for getting the behavior you are looking for.
From PHP.Net:
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";
}
?>
I would caution against relying on this behavior though and use break; for each case as that will remove some ambiguity when you revisit the code later.
Usually, it's recommended to write the most likely case first, the second one next...
but like Alex wrote,
This is likely going to be called a
micro optimisation. I don't believe
there would be a large difference.

Categories