使用箭头函数

箭头函数实际上是在 PHP 7.4 中首次引入的。但是,由于许多开发人员并不关注每一个版本的更新,因此在本书中介绍这一出色的新功能非常重要。

本节将介绍箭头函数及其语法,以及与匿名函数相比的优缺点。

通用语法

简单地说,箭头函数是传统 匿名函数 的一种速记语法,就像三元运算符是 if () {} else {} 的速记语法一样。箭头函数的通用语法如下所示:

fn(<ARGS>) => <EXPRESSION>

<ARGS> 是可选项,包括任何其他用户定义的 PHP 函数中出现的内容。<EXPRESSION> 可以包含任何标准的 PHP 表达式,如函数调用、算术运算等。

现在我们来看看箭头函数和匿名函数的区别。

箭头函数与匿名函数

在本小节中,您将学习箭头函数和匿名函数的区别。为了成为一名高效的 PHP 8 开发人员,了解箭头函数在何时何地可以替代匿名函数并提高代码性能非常重要。

在了解箭头函数之前,我们先来看一个简单的匿名函数。在下面的示例中,分配给 $addOld 的匿名函数产生了两个参数的和:

// /repo/ch02/php8_arrow_func_1.php
$addOld = function ($a, $b) { return $a + $b; };

在 PHP 8 中,可以得到完全相同的结果,如下所示:

$addNew = fn($a, $b) => $a + $b;

虽然代码的可读性大大提高,但这项新功能也有优缺点,本表对此进行了总结:

Table 1. Table 2.1 – Anonymous functions versus arrow functions
匿名函数 箭头函数

代码少

No

Yes

继承变量

需要 use()

Yes

可以被嵌套

Yes

Yes

自动绑定 $this

Yes

Yes

$$ 支持间接

Yes

No

多行代码

Yes

No

从上表可以看出,箭头函数比匿名函数更有效。不过,由于缺乏间接性和对多行的不支持,有时仍需要使用匿名函数。

变量继承

匿名函数与任何标准的 PHP 函数一样,只有在将变量值作为参数传递、使用全局关键字或添加 use() 修饰符的情况下,才能识别其作用域之外的变量。

下面是通过 use()DateTime 实例继承到匿名函数中的示例:

// /repo/ch02/php8_arrow_func_2.php
// not all code shown
$old = function ($today) use ($format) {
    return $today->format($format);
};

这是使用箭头函数完全相同的事情:

$new = fn($today) => $today->format($format);

正如你所看到的,语法非常简洁易读。现在我们来看看一个包含箭头函数的实际例子。

实际示例:使用箭头函数

回到制作难以阅读的验证码的想法(在第 1 章 "PHP 8 OOP 新特性介绍" 中首次提出),让我们来看看加入箭头函数可以如何提高效率和减少所需的编码量。现在我们来看看一个生成基于文本的验证码的脚本,如下所示:

  1. 首先,我们定义了一个函数,用于生成一个由随机选择的字母、数字和特殊字符组成的字符串。请注意下面的代码片段使用了新的 PHP 8 匹配表达式和箭头函数(高亮显示):

    // /repo/ch02/php8_arrow_func_3.php
    function genKey(int $size) {
        $alpha1 = range('A','Z');
        $alpha2 = range('a','z');
        $special = '!@#$%^&*()_+,./[]{}|=-';
        $len = strlen($special) - 1;
        $numeric = range(0, 9);
        $text = '';
        for ($x = 0; $x < $size; $x++) {
            $algo = rand(1,4);
            $func = match ($algo) {
                1 => fn() => $alpha1[array_rand($alpha1)],
                2 => fn() => $alpha2[array_rand($alpha2)],
                3 => fn() => $special[rand(0,$len)],
                4 => fn() => $numeric[array_rand($numeric)],
                default => fn() => ' '
            };
            $text .= $func();
        }
        return $text;
    }
  2. 然后,我们定义一个 textCaptcha() 函数来生成文本验证码。我们首先定义两个表示算法和颜色的数组。然后,对这两个数组进行洗牌,以进一步实现随机化。我们还定义了超文本标记语言(HTML<span> 元素来生成大小不同的字符,如下面的代码片段所示:

    function textCaptcha(string $text) {
        $algos = ['upper','lower','bold',
            'italics','large','small'];
        $color = ['#EAA8A8','#B0F6B0','#F5F596',
            '#E5E5E5','white','white'];
        $lgSpan = '<span style="font-size:32pt;">';
        $smSpan = '<span style="font-size:8pt;">';
        shuffle($algos);
        shuffle($color);
  3. 接下来,我们定义一系列 InfiniteIterator 实例。这是一个非常有用的标准 PHP 库(SPL)类,它允许你继续调用 next(),而不必检查是否迭代结束。这个迭代器类的作用是自动将指针移回数组的顶端,使您可以无限迭代。代码见以下代码段:

    $bkgTmp = new ArrayIterator($color);
    $bkgIter = new InfiniteIterator($bkgTmp);
    $algoTmp = new ArrayIterator($algos);
    $algoIter = new InfiniteIterator($algoTmp);
    $len = strlen($text);
  4. 然后,我们采用适当的算法和背景颜色,逐个字符创建文字验证码,如下所示:

        $captcha = '';
        for ($x = 0; $x < $len; $x++) {
            $char = $text[$x];
            $bkg = $bkgIter->current();
            $algo = $algoIter->current();
            $func = match ($algo) {
                'upper' => fn() => strtoupper($char),
                'lower' => fn() => strtolower($char),
                'bold' => fn() => "<b>$char</b>",
                'italics' => fn() => "<i>$char</i>",
                'large' => fn() => $lgSpan . $char . '</span>',
                'small' => fn() => $smSpan . $char . '</span>',
                default => fn() => $char
            };
            $captcha .= '<span style="background-color:'
                . $bkg . ';">'
                . $func() . '</span>';
            $algoIter->next();
            $bkgIter->next();
        }
        return $captcha;
    }

    请再次注意,为了达到预期效果,我们混合使用了 matcharrow 函数。脚本的其余部分只需调用这两个函数,如下所示:

    $text = genKey(8);
    echo "Original: $text<br />\n";
    echo 'Captcha : ' . textCaptcha($text) . "\n";

以下是 /repo/ch02/php8_arrow_func_3.php 在浏览器中的输出结果:

image 2023 11 20 16 55 24 803
Figure 1. Figure 2.4 – Output from php8_arrow_func_3.php

有关箭头函数的更多背景信息,请查看此处: https://wiki.php.net/rfc/arrow_functions_v2

有关 InfiniteIterator 的信息,请查看此处的 PHP 文档: https://www.php.net/InfiniteIterator

现在让我们看一下 统一变量语法