将匹配表达式合并到您的程序代码中

在 PHP 8 引入的众多令人难以置信的实用功能中,匹配表达式无疑是最引人注目的。匹配表达式是一种更精确的速记语法,有可能取代直接来自 C 语言的老式开关语句。在本节中,你将学习如何用匹配表达式取代 switch 语句,从而编写出更简洁、更准确的程序代码。

匹配表达式一般语法

Match 表达式的语法很像数组,其中键是要匹配的项,值是表达式。下面是 match 的一般语法:

$result = match(<EXPRESSION>) {
    <ITEM> => <EXPRESSION>,
    [<ITEM> => <EXPRESSION>,]
    default => <DEFAULT EXPRESSION>
};

表达式必须是有效的 PHP 表达式。表达式的例子可以包括以下任何一种:

  • 特定值(例如 "some text")

  • 操作(例如,$a + $b)

  • 匿名函数或类

唯一的限制是表达式必须在一行代码中定义。这里总结了 matchswitch 之间的主要区别:

Table 1. Table 1.1 – Differences between match and 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)项目,假设我们希望引入失真,使验证码字符更难阅读。为了实现这一目标,我们引入了一系列策略,每种策略都会产生不同的扭曲效果,具体如下表所示:

Table 2. Table 1.2 – CAPTCHA distortion strategy classes
Php8\Image\Strategy\* 描述

DotFill($num)

用 $num 点填充背景

LineFill($num)

用 $num 行填充背景

RotateText($angle)

按 $angle 旋转文本

Shadow($offset,$r,$g,$b)

添加相距 $offset 像素的阴影,颜色由 $r、$g 和 $b(红、绿、蓝)决定

在对要使用的策略列表进行随机化选择之后,我们使用 match 表达式来执行结果,如下所示:

  1. 首先,我们定义一个 自动加载器,导入要使用的类,并列出可能采用的策略,如下面的代码片段所示:

    // /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'];
  2. 接下来,我们生成验证码短语,如下所示:

    $phrase = strtoupper(bin2hex(random_bytes(NUM_BYTES)));
    $length = strlen($phrase);
  3. 然后,我们循环查看验证码短语中的每个字符,并创建一个 SingleChar 实例。首次调用 writeFill() 会创建白色背景画布。我们还需要调用 shuffle() 来随机化变形策略列表。下面的代码片段说明了这一过程:

    $images = [];
    for ($x = 0; $x < $length; $x++) {
        $char = new SingleChar($phrase[$x], FONT_FILE);
        $char->writeFill();
        shuffle($strategies);
  4. 然后,我们循环使用这些策略,并在原始图像上叠加变形。这就是匹配表达式发挥作用的地方。请注意,一个策略需要额外的代码行。由于 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);
    }
  5. 剩下的工作就是调用 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 容器:

image 2023 11 20 12 38 07 594
Figure 1. Figure 1.1 – Distorted CAPTCHA using match expression

接下来,我们来看看另一个非常棒的功能:命名参数

您可以在此处查看匹配表达式的原始提案: https://wiki.php.net/rfc/match_expression_v2