default as first option in switch statement?

2019-01-09 15:04发布

问题:

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?

回答1:

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;

}


回答2:

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.



回答3:

This is how I'd probably do it... it's easy on the eye and keeps the functionality.

switch($kind)
{
    case 'kind1': default :
        // 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;
}


回答4:

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.



回答5:

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;

}


回答6:

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)



回答7:

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.



回答8:

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.



回答9:

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.