Statements: Switch

A switch statement typically consists of a controlling expression, some case labels, and optionally a default label. Based on the value of the controlling expression, execution passes to one of the case labels, the default label, or to the statement immediately following the switch statement. For example:

enum Bank: int {
  DEPOSIT = 1;
  WITHDRAWAL = 2;
  TRANSFER = 3;
}

function processTransaction(Transaction $t): void {
  $trType = ...;     // get the transaction type as an enum value
  switch ($trType) {

  case Bank::TRANSFER:
    ...
    break;
  case Bank::DEPOSIT:
    ...
    break;
  case Bank::WITHDRAWAL:
    ...
    break;
  }
}

The switch has case labels for each of the possible value of enum Bank, where a case label is the keyword case followed by an expression, followed by :, followed by zero or more statements. Note that the so-called body of a case label need not be made a compound statement; the set of statements associated with a particular case label ends with a break statement or the closing brace (}) of the switch statement.

A default label is used as a catch-all. In the enumerated-type example above, assuming all possible values of type enum Bank have corresponding case labels, no default label is needed, as no other values can exist! However, that is not true when the switch controlling expression has type int. Here, we're unlikely to have case labels cover the complete range of int values, so a default label might be necessary. For example:

switch ($v) {
case 20:
  ...
  break;
case 10:
  ...
  break;
case 30:
  ...
  break;
default:
  ...
  break;
}

A default label is the keyword default, followed by :, followed by zero or more statements. Note that the so-called body of a default label need not be made a compound statement; the set of statements associated with a particular default label ends with a break statement or the closing brace (}) of theswitch` statement.

If a switch contains more than one case label whose values compare equal to the controlling expression, the first in lexical order is considered the match.

An arbitrary number of statements can be associated with any case or default label. In the absence of a break statement at the end of a set of such statements, control drops through into any following case or default label. Thus, if all cases and the default end in break and there are no duplicate-valued case labels, the order of case and default labels is insignificant.

If no break statement is seen for a case or default before a subsequent case label, default label, or the switch-terminating } is encountered, an implementation might issue a warning. However, such a warning can be suppressed by placing a source line containing the special comment // FALLTHROUGH, at the end of that case or default statement group.

Case-label values can be runtime expressions, and the types of sibling case-label values need not be the same.

$v = 10;
switch ($v) {
default:
  ...
  break;      // break ends "group" of default statements
case 20:
  ...
  break;      // break ends "group" of case 20 statements
case 10:
  ...
  // FALLTHROUGH
case 30:
  ...         // no break, but then none is really needed either
}
// -----------------------------------------
$v = 30;
switch ($v) {
case 30.0:  // <===== this case matches with 30
  ...
  break;
default:
  ...
  break;
case 30:    // <===== rather than this case matching with 30
  ...
  break;
}

Note carefully that the comparison of a switch value with its cases uses PHP's notion of equality, as implemented by the == operator, which can sometimes produce surprising results. See equality for more details.