switch ($value) 把一个值和一组 case 标签逐一比较,运行第一个匹配的标签下面的代码。每个 case 以 break 结束;default 处理所有都没匹配上的情况。
把 $day 改成 'fri'、'sun' 或 'wed',再运行一次。default 放在最后时不需要 break。
多个 case 共用一段代码
要让几个值运行同一段代码,就把 case 标签叠在一起,中间什么都不写。匹配的标签会接着运行下面的代码。
和 match 不同,switch 没有 case 'jpg', 'jpeg': 这样的逗号写法。叠加标签是唯一的办法。
贯穿:没有 break 会怎样
让 switch 停下来的是 break。没有它,PHP 运行完匹配的 case 后,会忽略下面各个 case 的标签,继续往下运行,直到遇到 break 或结尾。
这里的贯穿是有意的:每个套餐都拥有自己的功能,再加上所有更便宜套餐的功能。如果是故意这么写,加一行 // no break 这样的注释,免得后来的人把它“修好”。如果不是故意的,漏写 break 是 switch 最常见的 bug 之一。
switch 使用宽松比较(==)
每个 case 都用 == 检查,而不是 ===。数字字符串能匹配数字,null 能匹配 false 和 "",true 能匹配任何被当作真的值。点击单元格,对比这两个运算符。
| $a == $b | 0 | 1 | "0" | "1" | "" | null | false | true | "a" | "10" | "1e1" |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | |||||||||||
| 1 | |||||||||||
| "0" | |||||||||||
| "1" | |||||||||||
| "" | |||||||||||
| null | |||||||||||
| false | |||||||||||
| true | |||||||||||
| "a" | |||||||||||
| "10" | |||||||||||
| "1e1" |
实际影响是:表单传来的字符串 "1" 不用任何转换就能进入 case 1:,这往往正是你想要的。但 switch (true) 遇上非空字符串,或者 null 遇上 case false:,都可能选中你意想不到的 case。
注意 null 那一行:它永远到不了 case false:,因为 null == 0 已经为真,而 case 0: 排在前面。在宽松比较下,case 的顺序会改变结果。从 PHP 8 开始,0 == "a" 为假(PHP 7 中为真),所以非数字字符串不再匹配 case 0:。如果你需要 ===,用 match 表达式,本页最后会讲到。
用 switch(true) 判断范围和条件
case 标签可以是任意表达式。用 switch (true) 时,每个 case 都是一个条件,第一个等于 true 的胜出。
确保每个 case 都是真正的布尔值。由于是宽松比较,只要 $name 是非空字符串,case $name: 就会匹配。
循环中的 switch:break 和 continue
在循环里,switch 中的 break 只会跳出 switch,而不会跳出循环。要停止循环,用 break 2。switch 里的 continue 和 break 效果一样,PHP 会在编译时给出警告:"continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?。要跳到循环的下一轮,写 continue 2。
switch 与 match
PHP 8 新增了 match,它能用更少的代码覆盖 switch 的大多数用法。它用 === 比较,返回一个值,从不贯穿,允许用逗号分隔多个条件,而且在没有任何匹配时抛出 UnhandledMatchError,所以漏掉的 case 不会悄悄溜过去。
当一个 case 需要多条语句,或者贯穿正是你想要的效果(比如前面套餐的例子)时,继续用 switch。要把一个值映射成一个结果,match 更简短也更安全。
常见问题
PHP switch 中怎么让多个 case 共用一段代码?
把 case 标签叠在一起,中间不写代码:case 'sat': case 'sun': echo 'weekend'; break;。每个标签都会贯穿到共用的代码。PHP 的 switch 没有 case 'sat', 'sun': 这种写法,逗号形式属于 match。
PHP 的 switch 使用严格比较吗?
不是。switch 用宽松的 == 比较,所以 case '1': 能匹配整数 1,case 0: 能匹配 '0'。需要严格的 === 比较时,用 match 表达式,或者用 switch (true) 并在每个 case 里写 ===。
PHP switch 中忘了写 break 会怎样?
执行会贯穿下去:匹配的 case 运行完后,PHP 会继续运行它下面每个 case 的代码,直到遇到 break、return 或 switch 的结尾。有时这是有意为之,但通常是个 bug。
PHP switch 能判断“大于”这样的范围吗?
能,用 switch (true):每个 case 写一个条件,比如 case $score >= 90:,第一个为真的条件会被执行。match (true) 表达式用严格比较做同样的事,并返回一个值。