PHP 函数由 function 关键字、函数名、参数列表和函数体组成;return 把一个值返回给调用方。function add(int $a, int $b): int { return $a + $b; } 定义了函数,add(2, 3) 调用它并返回 5。
<?php
function greet(string $name): string
{
return "Hello, $name";
}
function add(int $a, int $b): int
{
return $a + $b;
}
echo greet('Ada'), "\n";
echo add(2, 3), "\n";
echo add(add(1, 2), 10), "\n";Master PHP the hands-on way
Interactive lessons, real projects, and instant feedback.
START NOW
参数前面的 string 和 int 是类型声明,括号后面的 : string 是返回类型。两者都是可选的,但它们能尽早发现错误,也说明了函数期望接收什么。
返回值与返回多个值
return 会立即结束函数。没有 return 的函数,或者只写了 return; 的函数,返回 null;如果函数只是为了它的副作用而被调用,就声明 : void。函数只返回一个值,但这个值可以是数组,你可以在调用方解构它:
<?php
function grade(int $score): string
{
if ($score >= 90) {
return 'A';
}
return $score >= 75 ? 'B' : 'C'; // reached only below 90
}
function stats(array $numbers): array
{
return [
'min' => min($numbers),
'max' => max($numbers),
'avg' => array_sum($numbers) / count($numbers),
];
}
function logLine(string $msg): void
{
echo "[log] $msg\n";
}
echo grade(95), grade(80), grade(40), "\n";
['min' => $min, 'max' => $max, 'avg' => $avg] = stats([4, 8, 15, 16, 23, 42]);
echo "min $min, max $max, average $avg\n";
[$quotient, $remainder] = [intdiv(17, 5), 17 % 5];
echo "17 / 5 = $quotient remainder $remainder\n";
var_dump(logLine('saved')); // a void function returns null
[...] = 的其他写法见数组解构 。
默认参数和命名参数
带有 = value 的参数是可选的:调用方可以省略它。可选参数放在必需参数之后。从 PHP 8.0 开始,命名参数让调用方可以按名字传递任意参数,这样你就能跳过不需要的可选参数。
<?php
function makeTag(string $text, string $tag = 'p', ?string $class = null, bool $escape = true): string
{
$body = $escape ? htmlspecialchars($text) : $text;
$attr = $class !== null ? " class=\"$class\"" : '';
return "<$tag$attr>$body</$tag>";
}
echo makeTag('Hello'), "\n";
echo makeTag('Title', 'h1'), "\n";
// Named arguments: skip $tag and $class, set only $escape
echo makeTag('<b>bold</b>', escape: false), "\n";
echo makeTag(class: 'note', text: 'Order does not matter'), "\n";
命名参数也能让内置函数的调用更易读:str_pad('7', 3, '0', pad_type: STR_PAD_LEFT)。参数名会成为函数公开接口的一部分,所以重命名参数可能会破坏使用参数名调用的代码。
引用传递
通常 PHP 传递的是每个实参的副本,所以函数无法修改调用方的变量。参数前的 & 会传递变量本身。像 sort() 这样的内置函数就是这样工作的。
<?php
function addOne(int $n): void
{
$n++; // changes the copy only
}
function addOneRef(int &$n): void
{
$n++; // changes the caller's variable
}
$a = 5;
addOne($a);
echo $a, "\n";
addOneRef($a);
echo $a, "\n";
function addItem(array &$cart, string $item): void
{
$cart[] = $item;
}
$cart = [];
addItem($cart, 'apple');
addItem($cart, 'pear');
print_r($cart);
返回一个新值通常比修改参数更清晰。只有当函数确实要原地修改某个东西时,才使用引用。
类型声明和 strict_types
默认情况下,PHP 会尽可能把实参转换成声明的类型:add("5", 3) 会把 "5" 变成 5。在文件最顶部写上 declare(strict_types=1);,就会对该文件中发出的调用关闭这种转换,于是类型不对时会抛出 TypeError,而不是被转换。
<?php
declare(strict_types=1);
// This throws a TypeError on purpose: "5" is a string, not an int
function add(int $a, int $b): int
{
return $a + $b;
}
echo add(2, 3), "\n";
echo add("5", 3), "\n";
去掉 declare 这一行,同样的调用会输出 8。不是数字的字符串(比如 "five")在两种模式下都会抛出 TypeError。
参数和返回值可以声明的类型:
<?php
// ?string: a string or null
function findUser(int $id): ?string
{
$users = [1 => 'Ada', 2 => 'Linus'];
return $users[$id] ?? null;
}
// int|float: a union type (PHP 8.0)
function half(int|float $n): float
{
return $n / 2;
}
// mixed: anything at all
function describe(mixed $value): string
{
return get_debug_type($value);
}
var_dump(findUser(1), findUser(9));
var_dump(half(5), half(2.5));
echo describe([1, 2]), ' ', describe(null), ' ', describe(1.5), "\n";
never 是一种返回类型,用于总是抛出异常或退出的函数。类名和接口名也可以用作类型。
用 ...$args 接收可变数量的参数
...$numbers 会把任意数量的实参收集到一个数组里。在调用方使用同样的 ...,则会把数组展开成多个独立的实参。
<?php
function sum(int ...$numbers): int
{
return array_sum($numbers);
}
echo sum(), "\n";
echo sum(1, 2, 3), "\n";
$values = [10, 20, 30];
echo sum(...$values), "\n"; // spread an array
function logMessage(string $level, string ...$parts): string
{
return strtoupper($level) . ': ' . implode(' ', $parts);
}
echo logMessage('info', 'user', 'Ada', 'logged in'), "\n";
在函数内使用外部变量
函数有自己的作用域。在函数外定义的变量在函数内不可见,这常常让从 JavaScript 转过来的人感到意外:
<?php
$taxRate = 0.2;
function priceWithTax(float $price): float
{
return $price * (1 + $taxRate); // $taxRate is undefined here
}
Warning: Undefined variable $taxRate in /path/to/index.php on line 6
而且函数返回的是不含税的价格。正确的做法是把这个值作为参数传进去。这样函数依赖什么一目了然,也便于测试:
<?php
$taxRate = 0.2;
function priceWithTax(float $price, float $taxRate): float
{
return $price * (1 + $taxRate);
}
echo priceWithTax(100, $taxRate), "\n";
echo priceWithTax(100, 0.1), "\n";
global 关键字也能用,但它会把依赖关系藏起来;变量作用域 介绍了它。对于传给其他函数的短小函数,比如 array_map() 的回调,请看匿名函数 ,它可以用 use 捕获外部变量。