PHP 完全指南 / 第 7 章 — 函数
第 7 章 — 函数:命名参数、可变参数、箭头函数与闭包
7.1 函数基础
<?php
declare(strict_types=1);
// 基本函数定义
function greet(string $name): string
{
return "Hello, {$name}!";
}
echo greet('Alice'); // Hello, Alice!
// 函数命名规范:camelCase 或 snake_case(PSR 推荐 camelCase)
function calculateTotal(float $price, int $quantity): float
{
return $price * $quantity;
}
7.2 命名参数(Named Arguments)— PHP 8.0+
<?php
function createUser(
string $name,
int $age = 18,
string $email = '',
bool $active = true,
): array {
return compact('name', 'age', 'email', 'active');
}
// 传统调用 — 必须按顺序
createUser('Alice', 30, '[email protected]', false);
// 命名参数 — 可跳过默认参数,顺序任意
createUser('Bob', email: '[email protected]');
createUser(
active: false,
name: 'Eve',
age: 25,
);
// 配合内置函数
htmlspecialchars($string, double_encode: false);
str_contains($haystack, 'needle', offset: 5);
array_map(callback: fn($n) => $n * 2, array: [1, 2, 3]);
注意:命名参数与函数签名参数名绑定,重命名参数属于 BC Break(向后不兼容)。
7.3 默认参数值
<?php
function sendEmail(
string $to,
string $subject,
string $body = '',
string $from = '[email protected]',
bool $isHtml = false,
int $priority = 3,
): bool {
// 发送逻辑...
return true;
}
// 使用默认值
sendEmail('[email protected]', 'Welcome');
// 覆盖部分默认值
sendEmail(
'[email protected]',
'Report',
body: '<h1>月报</h1>',
isHtml: true,
);
7.4 可变参数(Variadic Arguments)
7.4.1 ... 运算符
<?php
// 接收不定数量参数
function sum(int ...$numbers): int
{
return array_sum($numbers);
}
echo sum(1, 2, 3); // 6
echo sum(1, 2, 3, 4, 5); // 15
// 合并数组为参数
$values = [10, 20, 30];
echo sum(...$values); // 60(展开运算符)
7.4.2 带类型约束的可变参数
<?php
function log(string $level, string ...$messages): void
{
$timestamp = date('Y-m-d H:i:s');
foreach ($messages as $msg) {
echo "[{$timestamp}] [{$level}] {$msg}\n";
}
}
log('INFO', 'User logged in', 'Session started');
7.4.3 引用可变参数
<?php
function incrementAll(int &...$values): void
{
foreach ($values as &$value) {
$value++;
}
}
$a = 1; $b = 2; $c = 3;
incrementAll($a, $b, $c);
echo "$a, $b, $c"; // 2, 3, 4
7.5 箭头函数(Arrow Functions)— PHP 7.4+
<?php
// 语法:fn(参数) => 表达式
$double = fn(int $x): int => $x * 2;
echo $double(5); // 10
// 自动捕获外部变量(不需要 use)
$factor = 3;
$triple = fn(int $x): int => $x * $factor;
echo $triple(5); // 15
// 数组操作中常用
$prices = [100, 200, 300];
// 提取价格加税
$withTax = array_map(fn($p) => $p * 1.13, $prices);
// 过滤大于 150 的价格
$expensive = array_filter($prices, fn($p) => $p > 150);
// 排序
$sorted = array_values($prices);
usort($sorted, fn($a, $b) => $a <=> $b);
// 链式调用
$result = array_map(
fn($user) => $user['name'],
array_filter(
$users,
fn($user) => $user['age'] >= 18
)
);
箭头函数 vs 匿名函数
| 特性 | 箭头函数 fn() => | 匿名函数 function() {} |
|---|---|---|
| 语法 | 单表达式 | 多语句代码块 |
| 外部变量 | 自动捕获 | 需要 use |
return | 隐式 | 必须显式 |
| 适合场景 | 简单回调 | 复杂逻辑 |
7.6 闭包(Closures)
<?php
// 基本闭包
$greet = function(string $name): string {
return "Hello, {$name}!";
};
echo $greet('World');
// 使用 use 捕获外部变量
$multiplier = 10;
$scale = function(int $x) use ($multiplier): int {
return $x * $multiplier;
};
echo $scale(5); // 50
// 引用捕获
$count = 0;
$increment = function() use (&$count): int {
return ++$count;
};
$increment(); $increment(); $increment();
echo $count; // 3
// 闭包作为返回值 — 函数工厂
function createAdder(int $base): Closure
{
return function(int $value) use ($base): int {
return $base + $value;
};
}
$add5 = createAdder(5);
$add10 = createAdder(10);
echo $add5(3); // 8
echo $add10(3); // 13
7.6.1 闭包绑定(bind/bindTo)
<?php
class Logger
{
private array $logs = [];
public function getLogs(): array
{
return $this->logs;
}
}
$logAccessor = Closure::bind(
function(Logger $logger, string $message) {
$logger->logs[] = "[{$this->timestamp()}] {$message}";
},
new class { // 绑定到匿名类(可访问其 $this)
private function timestamp(): string
{
return date('Y-m-d H:i:s');
}
},
Logger::class
);
$logger = new Logger();
$logAccessor($logger, 'Test message');
print_r($logger->getLogs());
7.7 第一类可调用语法(First-class Callable)— PHP 8.1+
<?php
// 将函数/方法转为闭包对象
$strlen = strlen(...); // 函数
echo $strlen('hello'); // 5
$trim = trim(...);
$clean = array_map($trim, [' hello ', ' world ']);
// 静态方法
$validate = Email::validate(...);
// 对象方法
$obj = new Calculator();
$add = $obj->add(...);
// 数学函数
$square = fn(int $x) => ($x ** 2);
$sum = array_sum(array_map($square, [1, 2, 3, 4])); // 30
7.8 递归函数
<?php
// 阶乘
function factorial(int $n): int
{
if ($n <= 1) return 1;
return $n * factorial($n - 1);
}
echo factorial(5); // 120
// 斐波那契(带缓存)
function fibonacci(int $n, array &$memo = []): int
{
if (isset($memo[$n])) return $memo[$n];
if ($n <= 1) return $n;
$memo[$n] = fibonacci($n - 1, $memo) + fibonacci($n - 2, $memo);
return $memo[$n];
}
echo fibonacci(10); // 55
// 递归遍历目录
function scanDir(string $dir): array
{
$results = [];
foreach (new DirectoryIterator($dir) as $file) {
if ($file->isDot()) continue;
$path = $file->getPathname();
if ($file->isDir()) {
$results = array_merge($results, scanDir($path));
} else {
$results[] = $path;
}
}
return $results;
}
7.9 生成器函数(简介)
<?php
// 生成器使用 yield 产生值
function range2(int $start, int $end, int $step = 1): Generator
{
for ($i = $start; $i <= $end; $i += $step) {
yield $i;
}
}
foreach (range2(1, 10, 2) as $num) {
echo "{$num} ";
}
// 1 3 5 7 9
详见 第 14 章 — 生成器
7.10 类型化返回值进阶
<?php
// never 返回类型(PHP 8.1+)— 函数永不正常返回
function throwError(string $message): never
{
throw new RuntimeException($message);
}
// 交叉类型返回(PHP 8.1+)
interface Countable {}
interface Iterator {}
function createCollection(): Countable&Iterator
{
return new ArrayObject([1, 2, 3]);
}
7.11 业务场景:中间件管道
<?php
declare(strict_types=1);
// 闭包实现中间件模式
type Middleware = Closure;
function createPipeline(): Closure
{
return function (array $request, Closure $next) use (&$middlewares) {
// 管道会依次调用每个中间件
};
}
function buildMiddlewareStack(array $middlewares): Closure
{
// 将中间件链组合为单个闭包
$core = fn(array $request): array => $request;
return array_reduce(
array_reverse($middlewares),
fn(Closure $next, Closure $middleware): Closure =>
fn(array $request) => $middleware($request, $next),
$core
);
}
// 定义中间件
$logMiddleware = function(array $request, Closure $next): array {
echo "[LOG] {$request['method']} {$request['path']}\n";
$response = $next($request);
echo "[LOG] Status: {$response['status']}\n";
return $response;
};
$authMiddleware = function(array $request, Closure $next): array {
if (!isset($request['user'])) {
return ['status' => 401, 'body' => 'Unauthorized'];
}
return $next($request);
};
$timingMiddleware = function(array $request, Closure $next): array {
$start = microtime(true);
$response = $next($request);
$elapsed = round((microtime(true) - $start) * 1000, 2);
$response['elapsed_ms'] = $elapsed;
return $response;
};
// 构建管道
$pipeline = buildMiddlewareStack([
$logMiddleware,
$timingMiddleware,
$authMiddleware,
]);
// 执行
$response = $pipeline([
'method' => 'GET',
'path' => '/api/users',
'user' => ['id' => 1, 'name' => 'Alice'],
]);
print_r($response);
7.12 扩展阅读
上一章:第 6 章 — 控制流 下一章:第 8 章 — 数组