在switch语句中将默认选项作为第一选项?

21

我测试过了,它可以正常工作,但是看起来...有点奇怪...。我应该担心这是非标准形式,在未来的PHP版本中会被取消,或者它可能停止工作吗?我一直将默认情况作为最后一个情况,而不是第一个情况...

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...

(如果不明确,我的目的是确保$kind是有效的,因此使用默认情况:case。但是,switch还执行一些操作,然后在switch之后也使用$kind。这就是为什么默认情况:落到第一个情况,并且还设置了$kind)
建议?这是否正常/有效的语法?

还想提一下 - 我并不是 PHP 新手。我只是想听听其他 PHP 专家的意见。 - Josh
我个人这样做是因为默认选项是表单中的第一个选项,如果用户没有选择任何选项,那么阅读按顺序排列的选项将更容易...而默认是第一个。我只是来确认它能够工作。 - Jeff Davis
5
在编程中,当我们发现需要以一种“非传统”的方式解决问题时,最佳实践是在开关上方留下注释,解释为什么要以这种方式编写代码。 - Charles D Pantoga
default: comes for me first, always, period. Reason 1: It is semantically more correct. on default do this, but with special case 'kind1' do something else altogether. Reason 2: I will never forget to specify a default: - theking2
9个回答

29

这是一个不寻常的习惯用语,读到它时可能会稍微停顿一下,有一瞬间的“啥?”感觉。它确实有效,但大多数人可能会期望在结尾处找到默认情况:

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;

}

我同意,我在10多年的编程中编写的所有其他开关都是这样的。 但在这个特殊情况下,如果我像那样写,我需要两个开关语句。 - Josh
2
好的,我撤回之前的话。我需要:case 'kind1': default: $kind='kind1'; - Josh
好的,抱歉,我不知道为什么在你的回答中错过了那个。为了清晰起见,我可能会选择那条路线。 - Josh
在很多人的初始反应与我的相同之后,我决定这是正确的做法。 - Josh
如果您希望默认情况下选择第一个案例,并且您认为将第一个案例放在最前面而不是最后面更有意义,例如当案例被编号时,那么将默认情况放在最前面是很有用的。DanielM 在下面回答了这个问题。这样也更易读。 - Andrew

13

如果有人像我一样通过谷歌找到这个页面:

我和Josh有同样的疑问——... 一个是标准,我认为我们都应该更加努力地遵守,但另一件事是黑客行为(以:利用每一种可能性的方式)。

虽然这很丑陋/奇怪/不正常,但确实是可能的,并且在某些罕见情况下可能会有用...

考虑以下内容:

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

如果$color = "greenish";,代码将会输出:

未选择颜色,因此颜色为红色

而如果$color = "green";或任何其他已定义的情况,它只会打印颜色。

我知道这不是最好的例子,但你明白了吧 ;) 希望能对某些人有所帮助。


5
这是我可能会这样做的方式……它看起来很舒适,同时保持了功能性。
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;
}

1
起初我有疑问default:是否会使PHP忽略语句的其余部分,但这确实可行! - kbtz
虽然你的例子更易读且不那么含糊,但我认为作者利用默认情况来设置 $kind 变量的默认值,然后通过下一个 case 语句继续执行默认操作。如果代码依赖于该变量,则这可能很有用。基本上,这使得 case 'kind1': 成为无效数据的默认操作以及有效数据的选项,并同时减少了代码冗余。 - RisingSun
@RisingSun 感谢您的指出!这个答案至少错误了10年。我已经进行了更正。 - Frankie

5

由于同样的原因,它看起来很奇怪。

else {
   echo "lol";
}
if (1 == 1) {
   echo "bbq";
}

如果它是有效的话,看起来会很奇怪。仅因为这个原因,我会避免使用它。

此外,您知道每次向某人展示代码时,您将不得不解释首先放置 default 情况是故意的;通常这是一个不好的迹象。


2
我发誓我耸了耸肩。起初我不知道什么更奇怪,是else first还是1==1...只是让我感到困惑,加1。 - Khez

3

我个人更倾向于做

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;

}

谢谢,这就是我决定要做的。不过我选择接受保罗的答案,因为他回答得更快。但还是给你点赞 :-) - Josh
是啊,这种事情经常发生——很糟糕!抱歉 :-) - Josh

3
这对流程控制非常有用,特别是在不在case之间断开的情况下。
例如:
$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
}

您可以添加一个额外的“if”语句或巧妙地使用“or”语句,在开始切换之前将$step默认设置为'step1',但这只是额外的代码,会降低可读性。

这是因为将默认情况放在第一位很有用,如果您希望默认情况默认为第一个情况,并且您觉得将第一个情况放在第一位更有意义,而不是最后一位...就像它们按此编号时。 - Andrew

2

通常的做法是将默认选项定义为最后一个选项。但是我认为你的解决方案也没有问题(如果你公司没有预定义布局代码的模式)


很酷,谢谢。作为我们公司的首席开发人员,我有机会设立先例 :-) (这也是我选择道路前想要听取他人意见的另一个原因)。 - Josh
然后,您应该在 switch 语句的最后一个选项中将标准设置为默认值。这对大多数程序员来说看起来很“正常”。 - Henrik P. Hessel
而且由于代码中的其他所有开关语句都是这样的,我同意。谢谢! - Josh
你不是想把那个作为先例吧?那会让未来的开发人员感到不舒服! - Mez
为什么不呢?我以前从未见过Josh的布局 :) 而且我几年前做了很多PHP *g - Henrik P. Hessel

2

一开始让我有些不适,但那只是因为我们不习惯以这种方式看待事物。

我建议您对此进行详细记录,因为有些人可能会称这为“棘手”的代码。一个新手或未来的维护者可能会将其移动到底部,而破坏它在顶部具有的副作用。


1
其他答案给了很好的例子,为了澄清起见...
一个包括默认情况的 case 在没有包含 break 的情况下不会在其结尾停止执行。虽然 switch 经常被比作 if elseif elseif 等序列,但它并不完全是那样。
简短版本:只有在每个 case 后面包含 break 时,SWITCH/CASE 才像 IF/ELSEIF/ELSE 那样运行。SWITCH/CASE 更像一系列“if”语句,每个语句都具有相同的变量检查和不同的值进行检查。
长版本:如果不包含 break,则每个 case 都是“从这里开始”,在很多方面的差异使其更接近 GOTO 而没有缺点。技术上讲,如果你真的非常想(读者,是一个想要挑战自己的受虐待狂程序员),你可以使用仅一个外部数组、一个 for 循环和一个嵌套在其中的 switch 编写几乎任何过程化程序。
说真的,为什么你想这样做我无法理解,但它确实展示了 switch/case 可以偏离 if/elseif 模式的程度,因此出于学术原因,我们在这里提供它(但不要这样做!)。
$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']++;
    }
}

这段代码运行的方式(在设置捕获和设置选项后)是:它将启动并开始执行。
"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

所以...你可以使用开关来回到BASIC的时代... 但是如果你这样写了所有的代码,然后我之后必须调试它... 愿Linus Torvalds怜悯你的灵魂。


1
我不明白为什么这个被踩了。我只是想要澄清一下功能而已。 - lilHar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接