match ($value) { ... } 用严格的 === 把一个值和一组分支逐一比较,并返回第一个匹配分支的结果。多个值可以共用一个分支,default 负责处理其余的值,如果没有任何分支匹配,PHP 会抛出 UnhandledMatchError。
注意右花括号后面的分号:match 是一个表达式,就像 1 + 2 一样,所以整段代码是一条赋值语句。每个分支的形式是 values => result,分支之间用逗号分隔,最后一个分支后面也可以带一个逗号。
一个分支匹配多个值
用逗号列出这些值。只要主体与其中任意一个全等(===),这个分支就匹配。
像这里一样在函数中直接返回 match,是它最常见的用法。
match 与 switch 的区别
下面用两种写法实现同一个映射,其中一个输入展示了两者最大的区别:比较方式。switch 使用 ==,所以字符串 "1" 会匹配 case 1。match 使用 ===,所以不会匹配。
match | switch | |
|---|---|---|
| 比较方式 | 严格的 === | 松散的 == |
| 结果 | 返回一个值 | 语句,不返回任何值 |
| 贯穿 | 从不 | 会,直到遇到 break |
| 多个值 | 1, 2 => | 叠写 case 1: case 2: |
| 没有匹配 | 抛出 UnhandledMatchError | 什么都不做 |
| 分支内容 | 一个表达式 | 任意多条语句 |
当你要把一个值转换成另一个值时,使用 match。当一个分支需要多条语句,或者正需要贯穿时,继续使用 switch;switch 页面 介绍了这两种情况。
UnhandledMatchError:没有分支匹配时
没有 default 分支时,一个什么都匹配不上的值会导致错误,而不是默默返回 null。这其实是一项特性:新增的状态码或拼写错误会大声报错,而不是悄悄溜过去。
PHP 会停止运行并提示 PHP Fatal error: Uncaught UnhandledMatchError: Unhandled match case of type string。在开发环境中(zend.exception_ignore_args 关闭时),错误信息会直接给出这个值:Unhandled match case 'XL'。修复方法有两种:添加 default => 'other',或者在预期会出现未知值的地方捕获这个错误:
用 match(true) 判断范围和条件
match 会把主体与每个分支比较,所以如果主体是 true,每个分支都可以是一个条件。第一个求值结果恰好为 true 的条件胜出。
这段代码中有两个细节。从 PHP 8 开始,throw 是一个表达式,所以它可以作为分支的结果。另外,由于比较是严格的,每个条件都必须返回真正的布尔值:像 $name => ... 这样的分支永远不会匹配 true,即使 $name 是非空字符串也一样。只有匹配的分支才会被求值,所以 throw 只在年龄为负数时才会执行。
配合枚举使用 match
match 和枚举是绝配:在枚举方法中,match ($this) 可以把每个 case 映射到一个值。关于枚举本身,请参阅 PHP 枚举。
这里故意没有写 default。如果以后有人加了第五个 case,对它调用 color() 时会抛出错误,而不是返回一个错误的颜色。
在一个分支中执行多条语句
一个分支只能包含一个表达式,所以 'save' => { ...; ... } 不是合法的 PHP 代码。把这些操作移到一个函数中,再在分支中调用它。不匹配的分支中的函数永远不会被调用。
把 $format 改成 'json' 或 'xml',再运行一次。
常见问题
PHP 中 match 和 switch 有什么区别?
match 用严格的 === 比较,会返回一个值,永远不会贯穿到下一个分支,每个分支可以接受多个用逗号分隔的值,没有分支匹配时会抛出 UnhandledMatchError。switch 用松散的 == 比较,它是一条不返回任何值的语句,没有 break 就会贯穿,没有 case 匹配时也只是默默什么都不做。
PHP match 表达式中没有分支匹配时会发生什么?
PHP 会抛出 UnhandledMatchError。添加一个 default => ... 分支来处理其他所有值,或者用 try { ... } catch (\UnhandledMatchError $e) { ... } 捕获这个错误。
PHP 中怎么让 match 配合大于这样的条件使用?
对 true 进行匹配:match (true) { $age < 13 => 'child', $age < 18 => 'teen', default => 'adult' }。每个分支都是一个条件,第一个结果恰好为 true 的分支胜出。
PHP 中 match 的一个分支可以执行多条语句吗?
不可以,每个分支只能是一个表达式。把这些语句放进一个函数或方法,再在分支中调用它,例如 'export' => exportCsv($rows)。
match 是哪个 PHP 版本加入的?
PHP 8.0。在 PHP 7 中,同样的逻辑需要用 switch 语句或数组查找来实现,例如 $labels[$status] ?? 'Unknown'。