switch

(PHP 4, PHP 5, PHP 7, PHP 8)

switch 语句类似于对同一表达式的多个 IF 语句。在很多情况下,你可能希望将同一个变量(或表达式)与多个不同的值进行比较,并根据它等于哪个值来执行不同的代码块。这就是 switch 语句的作用。

注意: 请注意,与其他一些语言不同,continue 语句适用于 switch,其作用类似于 break。如果你在循环内有一个 switch,并且希望继续执行外层循环的下一个迭代,请使用 continue 2

注意:

请注意,switch/case 使用的是 松散比较

在下面的示例中,每个代码块都是等价的。一个使用一系列 ifelseif 语句,另一个使用 switch 语句。在每种情况下,输出都是相同的。

示例 #1 switch 结构

<?php
// 这个 switch 语句:

switch ($i) {
case
0:
echo
"i 等于 0";
break;
case
1:
echo
"i 等于 1";
break;
case
2:
echo
"i 等于 2";
break;
}

// 等价于:

if ($i == 0) {
echo
"i 等于 0";
} elseif (
$i == 1) {
echo
"i 等于 1";
} elseif (
$i == 2) {
echo
"i 等于 2";
}
?>

了解 switch 语句的执行方式非常重要,以避免错误。 switch 语句逐行(实际上是逐语句)执行。在开始时,没有代码被执行。只有当找到一个 case 语句,其表达式的计算结果与 switch 表达式的值匹配时,PHP 才会开始执行语句。PHP 会继续执行语句,直到 switch 块的末尾,或者它第一次遇到一个 break 语句。如果你没有在 case 语句列表的末尾写一个 break 语句,PHP 会继续执行下一个 case 语句的语句。例如

<?php
switch ($i) {
case
0:
echo
"i 等于 0";
case
1:
echo
"i 等于 1";
case
2:
echo
"i 等于 2";
}
?>

这里,如果 $i 等于 0,PHP 将执行所有 echo 语句!如果 $i 等于 1,PHP 将执行最后两个 echo 语句。只有当 $i 等于 2 时,你才会得到预期的行为(将显示 "i 等于 2")。因此,不要忘记 break 语句(即使你可能想故意不提供它们,在某些情况下)。

switch 语句中,条件只会被评估一次,结果会被与每个 case 语句进行比较。在 elseif 语句中,条件会被重新评估。如果你的条件比简单的比较更复杂,或者在紧密的循环中,switch 可能更快。

case 语句列表也可以为空,它只是将控制权传递到下一个 case 语句列表中。

<?php
switch ($i) {
case
0:
case
1:
case
2:
echo
"i 小于 3 但不为负";
break;
case
3:
echo
"i 等于 3";
}
?>

一个特殊的情况是 default case。这个 case 与其他 case 没有匹配的任何东西相匹配。例如

<?php
switch ($i) {
case
0:
echo
"i 等于 0";
break;
case
1:
echo
"i 等于 1";
break;
case
2:
echo
"i 等于 2";
break;
default:
echo
"i 不等于 0、1 或 2";
}
?>

注意: 多个 default case 会引发 E_COMPILE_ERROR 错误。

注意: 从技术上讲,default case 可以按任何顺序排列。它只会在没有其他 case 匹配时使用。但是,按照惯例,最好将它放在最后作为最后一个分支。

如果没有任何 case 分支匹配,并且没有 default 分支,那么将不会执行任何代码,就像没有 if 语句为真一样。

case 值可以被赋予为表达式。但是,该表达式将独立评估,然后与 switch 值进行松散比较。这意味着它不能用于对 switch 值进行复杂的评估。例如

<?php
$target
= 1;
$start = 3;

switch (
$target) {
case
$start - 1:
print
"A";
break;
case
$start - 2:
print
"B";
break;
case
$start - 3:
print
"C";
break;
case
$start - 4:
print
"D";
break;
}

// 输出 "B"
?>

对于更复杂的比较,可以使用值 true 作为 switch 值。或者,可以使用 if-else 块代替 switch

<?php
$offset
= 1;
$start = 3;

switch (
true) {
case
$start - $offset === 1:
print
"A";
break;
case
$start - $offset === 2:
print
"B";
break;
case
$start - $offset === 3:
print
"C";
break;
case
$start - $offset === 4:
print
"D";
break;
}

// Prints "B"
?>

switch 语句支持控制结构的替代语法。有关更多信息,请参见 控制结构的替代语法

<?php
switch ($i):
case
0:
echo
"i equals 0";
break;
case
1:
echo
"i equals 1";
break;
case
2:
echo
"i equals 2";
break;
default:
echo
"i is not equal to 0, 1 or 2";
endswitch;
?>

可以在 case 后面使用分号而不是冒号,例如

<?php
switch($beer)
{
case
'tuborg';
case
'carlsberg';
case
'stella';
case
'heineken';
echo
'Good choice';
break;
default;
echo
'Please make a new selection...';
break;
}
?>

另请参阅

添加注释

用户贡献的注释 7 notes

289
MaxTheDragon at home dot nl
12 年前
这在上面的文档中列出,但它被隐藏在段落之间。if 语句序列和 switch 语句之间的区别在于,在 switch 语句中,你比较的表达式只会被评估一次。我认为这个事实需要更多关注,所以这里有一个例子

<?php
$a
= 0;

if(++
$a == 3) echo 3;
elseif(++
$a == 2) echo 2;
elseif(++
$a == 1) echo 1;
else echo
"No match!";

// Outputs: 2

$a = 0;

switch(++
$a) {
case
3: echo 3; break;
case
2: echo 2; break;
case
1: echo 1; break;
default: echo
"No match!"; break;
}

// Outputs: 1
?>

因此,你可以放心地做

<?php
switch(winNobelPrizeStartingFromBirth()) {
case
"peace": echo "You won the Nobel Peace Prize!"; break;
case
"physics": echo "You won the Nobel Prize in Physics!"; break;
case
"chemistry": echo "You won the Nobel Prize in Chemistry!"; break;
case
"medicine": echo "You won the Nobel Prize in Medicine!"; break;
case
"literature": echo "You won the Nobel Prize in Literature!"; break;
default: echo
"You bought a rusty iron medal from a shady guy who insists it's a Nobel Prize..."; break;
}
?>

而无需担心函数对每个 case 都会重新评估。也不需要提前将结果保存到变量中。
122
septerrianin at mail dot ru
5 年前
php 7.2.8。
对永恒问题“哪个更快?”的答案
1 000 000 000 次迭代。

<?php
$s
= time();
for (
$i = 0; $i < 1000000000; ++$i) {
$x = $i%10;
if (
$x == 1) {
$y = $x * 1;
} elseif (
$x == 2) {
$y = $x * 2;
} elseif (
$x == 3) {
$y = $x * 3;
} elseif (
$x == 4) {
$y = $x * 4;
} elseif (
$x == 5) {
$y = $x * 5;
} elseif (
$x == 6) {
$y = $x * 6;
} elseif (
$x == 7) {
$y = $x * 7;
} elseif (
$x == 8) {
$y = $x * 8;
} elseif (
$x == 9) {
$y = $x * 9;
} else {
$y = $x * 10;
}
}
print(
"if: ".(time() - $s)."sec\n");

$s = time();
for (
$i = 0; $i < 1000000000; ++$i) {
$x = $i%10;
switch (
$x) {
case
1:
$y = $x * 1;
break;
case
2:
$y = $x * 2;
break;
case
3:
$y = $x * 3;
break;
case
4:
$y = $x * 4;
break;
case
5:
$y = $x * 5;
break;
case
6:
$y = $x * 6;
break;
case
7:
$y = $x * 7;
break;
case
8:
$y = $x * 8;
break;
case
9:
$y = $x * 9;
break;
default:
$y = $x * 10;
}
}
print(
"switch: ".(time() - $s)."sec\n");
?>

结果
if: 69秒
switch: 42秒
81
nospam at please dot com
23 年前
我学到的一点技巧

如果你需要评估多个变量来找到第一个具有实际值的变量(例如,TRUE),你可以用这种方式。

可能还有更好的方法,但这对我来说很有效。

switch (true) {

case (X != 1)

case (Y != 1)

default
}
5
me at czarpino dot com
1 年前
尽管在其他地方有提到,但仍然值得注意的是,switch-case 中的宽松比较也受到字符串到数字比较变化的影响。在 PHP8 之前,字符串在比较之前会被转换为整数。现在情况相反,这会导致依赖这种行为的逻辑出现问题。

<?php
function testSwitch($key) {
switch (
$key) {
case
'non numeric string':
echo
$key . ' matches "non numeric string"';
break;
}
}

testSwitch(0); // PHP8 之前,返回 '0 matches "non numeric string"'
?>
5
j dot kane dot third at gmail dot com
1 年前
默认情况似乎总是最后评估。如果从默认情况中排除 break,则将重新评估后续情况。这种行为似乎没有记录。

<?php

$kinds
= ['moo', 'kind1', 'kind2'];

foreach (
$kinds as $kind) {
switch(
$kind)
{
default:
// 该类型无效,将其设置为默认类型
$kind = 'kind1';
var_dump('default');

case
'kind1':
var_dump('1');
break;

case
'kind2':
var_dump('2');
break;

case
'kindn':
var_dump('n-th');
break;
}

echo
"\n\n";
}

?>
1
php at nospam dot k39 dot se
22 天前
可以通过一次检查多个情况来防止嵌套的 switch/match/if 块(只需注意 PHP 在这里使用宽松比较)。

<?php
$a
= "abc";
$b = "def";

switch ([
$a, $b]) {
case [
"abc", "def"]:
$result = 1;
break;
default:
$result = -1;
}
// $result == 1
?>

如果对于某些情况,其中一个值不重要,可以使用变量本身

<?php
$a
= "abc";
$b = "def";

switch ([
$a, $b]) {
case [
"xyz", "def"]:
$result = 1;
break;
case [
$a, "def"]:
$result = 2;
break;
default:
$result = -1;
}
// $result == 2
?>
-2
GeorgNation
9 个月前
你可以用大括号将 case/break 块括起来

$x = 2;

switch ($x)
{
case 2: {
echo '2 entrypoint';
break;
}

default: {
echo 'default entrypoint';
break;
}
}
To Top