switch statement without break

14,508

Solution 1

Fallthrough was an intentional design feature for allowing code like:

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

It's designed so that execution runs down from case to case.

default is a case like any other, except that jumping there happens if no other case was triggered. It is not by any means a "do this after running the actual selected case" instruction. In your example, you could consider:

  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;

The rule of thumb here is, if it doesn't depend on the switch, move it out of the switch.

Solution 2

Because that's how it's done in C.

Solution 3

Perhaps this will enlighten you:

Jump Table Switch Case question

Solution 4

I don't really see what you want.

  1. If you want to run the default stuff in all cases, just put it after the switch.
  2. If you want to run the default stuff only in the "created" case and in the default case, swap the position of the "created" and "Creator" sections and put a break after the first.
  3. If you want that code to only run if Creator or created matches, then get rid of the switch statement and use an if/else OR use a flag and a following if statement.

All the tools are there.

Solution 5

In PHP 8 we have match, similar with switch expression but is significantly shorter:

  • it doesn't require a break statement
  • it can combine different arms into one using a comma
  • it returns a value, so you only have to assign value once

An example:

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

Here's its switch equivalent:

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

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

Share:
14,508
Rene Terstegen
Author by

Rene Terstegen

Updated on June 14, 2022

Comments

  • Rene Terstegen
    Rene Terstegen almost 2 years

    How come a case option in a switch statement that does not contain a break automatically forwards to a next case without check?

    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();
    }
    

    If the param is "created" it will do the check in the created-case, which is good. When the check is succesful, I want the code to continue to the default option, that's why there is no break;. But instead it continues to "Creator" while $param != "Creator"!

    I do know how to solve this (just add the default code in my case "created"), but I don't like to repeat that code too often. My actual question is: Why does it continue with the "Creator" case while the case is not "Creator".

  • Morfildur
    Morfildur over 13 years
    I would add that - while fall-through is sometimes usefull - it's better to not use it where both cases do something instead of just falling through (Good: case "created": case "creator": case "something_else": do_stuff(); Bad: case "created": do_stuff(); case "creator": do_Second_stuff(); case "something_else": do_remaining_stuff();)
  • Rene Terstegen
    Rene Terstegen over 13 years
    It's not about what I want, it is about why a switch statement is working like this.
  • Victor Nicollet
    Victor Nicollet over 13 years
    @dbemerlin: it's indeed quite dangerous, though acceptable if the cases are short or in languages which support explicit fallthrough (like C#).
  • Hammerite
    Hammerite over 13 years
    Best is to add a comment to say fallthrough is intentional.
  • caveman
    caveman over 13 years
    I apologize that I misunderstood the question. History is the answer. Like most anything in programming, somebody said so. This is how they said. There's some history there (basically that C started it), but that is the syntax.