将匹配表达式合并到您的程序代码中
在 PHP 8 引入的众多令人难以置信的实用功能中,匹配表达式无疑是最引人注目的。匹配表达式是一种更精确的速记语法,有可能取代直接来自 C 语言的老式开关语句。在本节中,你将学习如何用匹配表达式取代 switch 语句,从而编写出更简洁、更准确的程序代码。
匹配表达式一般语法
Match
表达式的语法很像数组,其中键是要匹配的项,值是表达式。下面是 match
的一般语法:
$result = match(<EXPRESSION>) {
<ITEM> => <EXPRESSION>,
[<ITEM> => <EXPRESSION>,]
default => <DEFAULT EXPRESSION>
};
表达式必须是有效的 PHP 表达式。表达式的例子可以包括以下任何一种:
-
特定值(例如 "some text")
-
操作(例如,$a + $b)
-
匿名函数或类
唯一的限制是表达式必须在一行代码中定义。这里总结了 match
和 switch
之间的主要区别:
Switch | Match |
---|---|
松散类型比较(例如,$a == $b) |
严格类型比较(例如,$a === $b) |
不返回值 |
返回一个值 |
需要 break |
不需求 break |
每个 case 多个命令 |
一个 match 一个命令 |
除上述区别外,match 和 switch 都允许 case 聚合,并支持默认 case。
switch 和 match 示例
这是一个使用 switch 呈现货币符号的简单示例:
// /repo/ch01/php7_switch.php
function get_symbol($iso) {
switch ($iso) {
case 'CNY' :
$sym = '¥';
break;
case 'EUR' :
$sym = '€';
break;
case 'EGP' :
case 'GBP' :
$sym = '£';
break;
case 'THB' :
$sym = '฿';
break;
default :
$sym = '$';
}
return $sym;
}
$test = ['CNY', 'EGP', 'EUR', 'GBP', 'THB', 'MXD'];
foreach ($test as $iso)
echo 'The currency symbol for ' . $iso
. ' is ' . get_symbol($iso) . "\n";
执行该代码后,您将在 $test
数组中看到国际标准化组织(ISO)的每种货币代码的货币符号。在 PHP 8 中,使用以下代码可以获得与前面代码片段中相同的结果:
// /repo/ch01/php8_switch.php
function get_symbol($iso) {
return match ($iso) {
'EGP','GBP' => '£',
'CNY' => '¥',
'EUR' => '€',
'THB' => '฿',
default => '$'
};
}
$test = ['CNY', 'EGP', 'EUR', 'GBP', 'THB', 'MXD'];
foreach ($test as $iso)
echo 'The currency symbol for ' . $iso
. ' is ' . get_symbol($iso) . "\n";
如图所示,两个示例的输出结果完全相同:
The currency symbol for CNY is ¥
The currency symbol for EGP is £
The currency symbol for EUR is €
The currency symbol for GBP is £
The currency symbol for THB is ฿
The currency symbol for MXD is $
如前所述,这两个代码示例都为 $test
数组中存储的 ISO 货币代码列表生成了一个货币符号列表。
复杂匹配示例
回到我们的验证码(CAPTCHA)项目,假设我们希望引入失真,使验证码字符更难阅读。为了实现这一目标,我们引入了一系列策略,每种策略都会产生不同的扭曲效果,具体如下表所示:
Php8\Image\Strategy\* | 描述 |
---|---|
DotFill($num) |
用 $num 点填充背景 |
LineFill($num) |
用 $num 行填充背景 |
RotateText($angle) |
按 $angle 旋转文本 |
Shadow($offset,$r,$g,$b) |
添加相距 $offset 像素的阴影,颜色由 $r、$g 和 $b(红、绿、蓝)决定 |
在对要使用的策略列表进行随机化选择之后,我们使用 match
表达式来执行结果,如下所示:
-
首先,我们定义一个 自动加载器,导入要使用的类,并列出可能采用的策略,如下面的代码片段所示:
// /repo/ch01/php8_single_strategies.php // not all code is shown require_once __DIR__ . '/../src/Server/Autoload/Loader.php'; $loader = new \Server\Autoload\Loader(); use Php8\Image\SingleChar; use Php8\Image\Strategy\ {LineFill,DotFill,Shadow,RotateText}; $strategies = ['rotate', 'line', 'line', 'dot', 'dot', 'shadow'];
-
接下来,我们生成验证码短语,如下所示:
$phrase = strtoupper(bin2hex(random_bytes(NUM_BYTES))); $length = strlen($phrase);
-
然后,我们循环查看验证码短语中的每个字符,并创建一个
SingleChar
实例。首次调用writeFill()
会创建白色背景画布。我们还需要调用shuffle()
来随机化变形策略列表。下面的代码片段说明了这一过程:$images = []; for ($x = 0; $x < $length; $x++) { $char = new SingleChar($phrase[$x], FONT_FILE); $char->writeFill(); shuffle($strategies);
-
然后,我们循环使用这些策略,并在原始图像上叠加变形。这就是匹配表达式发挥作用的地方。请注意,一个策略需要额外的代码行。由于
match
只能支持一个表达式,我们只需将多行代码封装到一个 匿名函数 中即可,如下所示:foreach ($strategies as $item) { $func = match ($item) { 'rotate' => RotateText::writeText($char), 'line' => LineFill::writeFill( $char, rand(1, 10)), 'dot' => DotFill::writeFill($char, rand(10, 20)), 'shadow' => function ($char) { $num = rand(1, 8); $r = rand(0x70, 0xEF); $g = rand(0x70, 0xEF); $b = rand(0x70, 0xEF); return Shadow::writeText( $char, $num, $r, $g, $b);}, 'default' => TRUE }; if (is_callable($func)) $func($char); }
-
剩下的工作就是调用
writeText()
(不带参数),将图片与实际验证码短语叠加在一起。然后,我们将扭曲的图像保存为便携式网络图形 (PNG) 文件,以便显示,如下代码片段所示:$char->writeText(); $fn = $x . '_' . substr(basename(__FILE__), 0, -4) . '.png'; $char->save(IMG_DIR . '/' . $fn); $images[] = $fn; } include __DIR__ . '/captcha_simple.phtml';
下面是通过浏览器运行前述示例的结果,该浏览器指向与本书相关的 Docker 容器:

接下来,我们来看看另一个非常棒的功能:命名参数。
您可以在此处查看匹配表达式的原始提案: https://wiki.php.net/rfc/match_expression_v2 |