函数

函数是一个可重复使用的代码块,在给定输入的情况下执行一些操作,并返回一些结果。你已经知道一些预定义函数,如 emptyin_arrayvar_dump。这些函数是 PHP 自带的,所以你不必重新发明轮子,但你可以很容易地创建自己的函数。在确定应用程序中需要多次执行的部分或只是为了封装某些功能时,可以定义函数。

函数声明

声明函数意味着将其写下来,以便以后使用。函数有一个名称,接受一些参数,并有一个代码块。函数还可以定义返回值的类型。函数名必须遵循与变量名相同的规则,即必须以字母或下划线开头,可以包含任何字母、数字或下划线。不能使用保留字。

我们来看一个简单的例子:

function addNumbers($a, $b) {
    $sum = $a + $b;
    return $sum;
}
$result = addNumbers(2, 3);

前面的函数名为 addNumbers,它有两个参数: $a$b。代码块定义了一个新变量 $sum,它是两个参数的总和,然后用 return 返回其内容。要使用该函数,只需调用它的名称,同时发送所有需要的参数,如高亮显示行所示。

PHP 不支持重载函数。重载是指声明两个或多个名称相同但参数不同的函数。如您所见,您可以在不知道参数类型的情况下声明参数,因此 PHP 无法决定使用哪个函数。

另一个需要注意的地方是变量的作用域。我们在代码块中声明了一个变量 $sum,因此一旦函数结束,这个变量将不再被访问。也就是说,在函数内部声明的变量的作用域仅限于函数本身。此外,如果在函数外部声明了变量 $sum,它也不会受到任何影响,因为除非我们将其作为参数发送,否则函数无法访问该变量。

函数参数

函数通过参数从外部获取信息。您可以定义任意数量的参数,包括 0(无)。这些参数至少需要一个名称,以便在函数内部使用;不能有两个参数同名。调用函数时,需要按照声明的顺序发送参数。

函数可能包含可选参数,也就是说,您不必强制为这些参数赋值。在声明函数时,需要为这些参数提供默认值。因此,如果用户没有提供参数值,函数将使用默认值。

function addNumbers($a, $b, $printResult = false) {
    $sum = $a + $b;
    if ($printResult) {
        echo 'The result is ' . $sum;
    }
    return $sum;
}

$sum1 = addNumbers(1, 2);
$sum1 = addNumbers(3, 4, false);
$sum1 = addNumbers(5, 6, true); // it will print the result

上一个示例中的新函数包含两个必选参数和一个可选参数。可选参数的默认值为 false,在函数中正常使用。如果用户提供 true 作为第三个参数,函数将打印求和的结果,而这只发生在第三次调用函数时。在前两次中,$printResult 被设置为 false

函数接收的参数只是用户提供的值的副本。也就是说,如果在函数内部修改这些参数,将不会影响原始值。这一功能被称为按值发送参数。让我们来看一个例子:

function modify($a) {
    $a = 3;
}

$a = 2;
modify($a);
var_dump($a); // prints 2

我们声明了一个值为 2 的变量 $a,然后调用 modify 方法发送该 $amodify 方法修改了参数 $a,将其值设置为 3,但这并不影响 $a 的原始值,正如 var_dump 所示,它仍然是 2。

如果要真正改变调用中使用的原始变量的值,则需要通过引用来传递参数。为此,需要在声明函数时在参数前添加一个 &

function modify(&$a) {
    $a = 3;
}

现在,在调用函数 modify 时,$a 将始终为 3。

按值参数与按引用参数

PHP 允许这样做,事实上,PHP 的一些本地函数使用引用参数。还记得数组排序功能吗?它们并不返回排序后的数组,而是对提供的数组进行排序。但使用参数引用是一种混淆开发人员的方法。通常,当有人使用函数时,他们期望得到一个结果,而不希望自己提供的参数被修改。因此,请尽量避免这样做;人们会感激不尽的!

返回语句

您可以在函数中使用任意多的 return 语句,但 PHP 会在发现返回语句时立即退出函数。这意味着如果有两个连续的 return 语句,第二个将永远不会被执行。不过,如果在条件中使用多个返回语句,还是很有用的。在 functions.php 文件中添加此函数:

function loginMessage() {
    if (isset($_COOKIE['username'])) {
        return "You are " . $_COOKIE['username'];
    } else {
        return "You are not authenticated.";
    }
}

让我们在 index.php 文件中使用最后一个示例,替换高亮显示的内容(注意,为了节省一些空间,我用 //... 替换了大部分没有改动的代码):

//...
<body>
<p><?php echo loginMessage(); ?></p>
<?php if (isset($_GET['title']) && isset($_GET['author'])): ?>
//...

此外,如果不希望函数返回任何内容,也可以省略 return 语句。在这种情况下,函数将在代码块结束时结束。

类型提示和返回类型

随着 PHP 7 的发布,该语言允许开发人员更具体地说明函数的获取和返回。您可以—​始终是可选的—​指定函数所需的参数类型(类型提示),以及函数将返回的结果类型(返回类型)。让我们先来看一个例子:

<?php
declare(strict_types=1);

function addNumbers(int $a, int $b, bool $printSum): int {
    $sum = $a + $b;
    if ($printSum) {
        echo 'The sum is ' . $sum;
    }
    return $sum;
}

addNumbers(1, 2, true);
addNumbers(1, '2', true); // it fails when strict_types is 1
addNumbers(1, 'something', true); // it always fails

前面的这个函数说明,参数需要是整数、整型和布尔型,而结果将是一个整数。现在,我们知道 PHP 具有类型杂耍功能,因此它通常可以将一种类型的值转换为另一种类型的等价值,例如,字符串 "2" 可以用作整数 2。要阻止 PHP 对函数的参数和结果使用类型戏法,可以声明严格类型(strict_types)指令,如第一个突出显示的行所示。该指令必须声明在要强制执行该行为的每个文件的顶部。

三次调用的工作原理如下:

  • 第一次调用发送了两个整数和一个布尔值,这正是函数所期望的,因此无论 string_types 的值如何,它都能正常工作。

  • 第二次调用发送了一个整数、一个字符串和一个布尔值。字符串有一个有效的整数值,因此如果 PHP 允许使用类型戏法,调用就会正常解决。但在本例中,由于文件顶部的声明,调用会失败。

  • 第三次调用总是失败,因为字符串 "something" 无法转换为有效的整数。

让我们尝试在项目中使用函数。在 index.php 中,我们有一个 foreach 循环,用于遍历书籍并打印出来。循环内部的代码很难理解,因为它是 HTML 和 PHP 的混合体,而且还有一个条件。让我们尝试将循环内部的逻辑抽象为一个函数。首先,创建新的 functions.php 文件,内容如下:

<?php

function printableTitle(array $book): string {
    $result = '<i>' . $book['title'] . '</i> - ' . $book['author'];
    if (!$book['available']) {
        $result .= ' <b>Not available</b>';
    }
    return $result;
}

该文件将包含我们的函数。第一个函数是 printableTitle,它接收一个代表一本书的数组,并用 HTML 创建一个能很好地表示这本书的字符串。代码与之前的相同,只是封装在一个函数中。

现在,index.php 必须包含 functions.php 文件,然后在循环中使用该函数。让我们看看如何操作:

<?php require_once 'functions.php' ?>
<!DOCTYPE html>
<html lang="en">

//...

?>
    <ul>
<?php foreach ($books as $book): ?>
    <li><?php echo printableTitle($book); ?> </li>
<?php endforeach; ?>
    </ul>

//...

现在,我们的循环看起来更简洁了,对吗?另外,如果我们需要在其他地方打印书名,我们可以重复使用这个函数,而不是重复代码!