PHP Conference Japan 2024

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

// 输出 "B"
?>

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

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

另请参阅

添加注释

用户贡献的注释 6 个注释

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!";

// 输出: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;
}

// 输出: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 重新评估。也无需预先将结果保存在变量中。
septerrianin at mail dot ru
6 年前
php 7.2.8。
对永恒问题“哪个更快?”的解答
10 亿次迭代。



<?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秒
[email protected]
24年前
我只是学到一个小技巧

如果你需要评估多个变量以找到第一个具有实际值(例如 TRUE)的变量。你可以这样操作。

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

switch (true) {

case (X != 1)

case (Y != 1)

default
}
[email protected]
2年前
尽管在其他地方也提到了,但仍然值得注意的是,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"'
?>
[email protected]
4个月前
可以通过一次检查多个情况来避免嵌套的 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
?>
[email protected]
2年前
default case 似乎总是最后评估。如果从 default case 中排除 break,则将重新评估后续的 case。此行为似乎没有记录。

<?php

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

foreach (
$kinds as $kind) {
switch(
$kind)
{
default:
// kind 无效,将其设置为默认值
$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";
}

?>
To Top