【问题标题】:switch statement without break无间断的 switch 语句
【发布时间】:2011-05-08 12:26:20
【问题描述】:

switch语句中不包含break的case选项怎么会自动转发到下一个case而不检查?

try {
    switch($param) {
        case "created":
            if(!($value instanceof \DateTime))
                throw new \Exception("\DateTime expected, ".gettype($value)." given for self::$param");
        case "Creator":
            if(!($value instanceof \Base\User)) {
                throw new \Exception(get_class($value)." given. \Base\User expected for self::\$Creator");                  
            }
        default:
            $this->$param = $value;
            break;
    }
} catch(Exception $e) {
    echo $e->getMessage();
}

如果参数是“创建的”,它将在创建的情况下进行检查,这很好。当检查成功时,我希望代码继续使用默认选项,这就是为什么没有 break;。但相反,它在 $param != "Creator"! 时继续“创建者”!

我确实知道如何解决这个问题(只需在“创建”的情况下添加默认代码),但我不喜欢经常重复该代码。我的实际问题是:为什么它会继续使用“Creator”案例,而该案例不是“Creator”。

【问题讨论】:

    标签: php switch-statement


    【解决方案1】:

    Fallthrough 是一种有意的设计功能,允许以下代码:

    switch ($command) {
      case "exit":
      case "quit":
        quit();
        break;
      case "reset":
        stop();
      case "start":
        start();
        break;
    }
    

    它的设计是为了逐个执行。

    default 与任何其他情况一样,只是在没有触发其他情况时会跳转到那里。这绝不是“在运行实际选定的案例后执行此操作”指令。在您的示例中,您可以考虑:

      switch($param) {
        case "created":
            if(!($value instanceof \DateTime))
                throw new \Exception("\DateTime expected, ".gettype($value)." given for self::$param");
            break;
        case "Creator":
            if(!($value instanceof \Base\User)) {
                throw new \Exception(get_class($value)." given. \Base\User expected for self::\$Creator");                  
            }
            break;
    }
    
    $this->$param = $value;
    

    这里的经验法则是,如果它不依赖于交换机,则将其移出交换机。

    【讨论】:

    • 我要补充一点 - 虽然失败有时很有用 - 最好不要在两种情况下都使用它而不是仅仅失败(好:case "created": case "creator": case "something_else": do_stuff(); 坏:case "created": do_stuff(); case "creator": do_Second_stuff(); case "something_else": do_remaining_stuff();
    • @dbemerlin:这确实很危险,但如果案例很短或使用支持显式失败的语言(如 C#),这是可以接受的。
    • 最好是加一条评论,说fallthrough是故意的。
    【解决方案2】:

    因为它就是这样做的in C

    【讨论】:

      【解决方案3】:

      也许这会启发你:

      Jump Table Switch Case question

      【讨论】:

        【解决方案4】:

        我真的看不出你想要什么。

        1. 如果您想在所有情况下都运行默认内容,只需将其放在 switch 之后。
        2. 如果您只想在“已创建”情况和默认情况下运行默认内容,请交换“已创建”和“创建者”部分的位置,并在第一个部分之后放置一个中断。
        3. 如果您希望该代码仅在 Creator 或 created 匹配时运行,则摆脱 switch 语句并使用 if/else 或使用标志和后面的 if 语句。

        所有工具都在那里。

        【讨论】:

        • 这不是我想要什么,而是为什么 switch 语句会这样工作。
        • 我很抱歉我误解了这个问题。历史就是答案。就像编程中的大多数事情一样,有人这么说。他们是这样说的。那里有一些历史(基本上是 C 开始的),但这就是语法。
        【解决方案5】:

        在 PHP 8 中,我们有 match,与 switch 表达式类似,但要短得多:

        • 它不需要 break 语句
        • 它可以使用逗号将不同的手臂组合成一个
        • 它返回一个值,所以你只需要赋值一次

        一个例子:

        $message = match ($statusCode) {
            200, 300 => null,
            400 => 'not found',
            500 => 'server error',
            default => 'unknown status code',
        };
        

        这是它的 switch 等价物:

        switch ($statusCode) {
            case 200:
            case 300:
                $message = null;
                break;
            case 400:
                $message = 'not found';
                break;
            case 500:
                $message = 'server error';
                break;
            default:
                $message = 'unknown status code';
                break;
        }
        

        参考:https://stitcher.io/blog/php-8-match-or-switch

        【讨论】:

          【解决方案6】:

          回答您的“实际问题”:为什么它继续使用“创造者”案例,而案例不是“创造者”。

          因为你没有break。没有它,它将继续到它下面的案例。我能想到的唯一解决方案是将您的默认代码放入案例中,并添加break

          此外,默认情况下不需要break,因为它是 switch 块中的最后一个情况。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多