返回值
概述
返回值是函数将处理结果传递给调用者的方式。PHP 函数通过 return 语句返回值,支持多种返回类型声明,包括标量类型、联合类型、void 和 never。合理使用返回值类型声明可以显著提升代码的健壮性和可维护性。
PHP 版本说明
- 返回类型声明自 PHP 7.0 引入
void返回类型自 PHP 7.1 引入- 联合类型返回值自 PHP 8.0 引入
never返回类型自 PHP 8.1 引入static返回类型(延迟静态绑定)自 PHP 8.0 支持
基础概念
return 语句
return 语句用于终止函数执行并将值返回给调用者。一个函数可以有多个 return 语句,但每次调用只会执行其中一个。
php
function getStatus(int $score): string
{
if ($score >= 90) {
return 'excellent';
}
if ($score >= 60) {
return 'pass';
}
return 'fail';
}返回值类型系统
| 返回类型 | 引入版本 | 说明 |
|---|---|---|
| 无声明 | 所有版本 | 不声明类型,可以返回任何值 |
| 标量类型 | PHP 7.0 | int, float, string, bool |
array | PHP 7.0 | 返回数组 |
callable | PHP 7.0 | 返回可调用结构 |
self | PHP 7.0 | 返回当前类的实例 |
?T (nullable) | PHP 7.1 | 返回指定类型或 null |
void | PHP 7.1 | 无返回值或返回 null |
object | PHP 7.2 | 返回任意对象 |
iterable | PHP 7.1 | 返回数组或 Traversable |
static | PHP 8.0 | 延迟静态绑定返回 |
T1|T2 (联合) | PHP 8.0 | 返回多种类型之一 |
T&U (交叉) | PHP 8.1 | 返回同时满足多个接口的对象 |
never | PHP 8.1 | 函数永不返回(抛异常或终止) |
语法与代码
基本返回值
php
<?php
declare(strict_types=1);
function add(int $a, int $b): int
{
return $a + $b;
}
$result = add(3, 4);
echo $result . "\n"; // 7
// 返回值为 null 的情况
function returnNull(): ?string
{
return null;
}
var_dump(returnNull()); // NULL
// 没有 return 语句时返回 null
function noReturnStatement(): void
{
echo "This function has no return\n";
}
$voidResult = noReturnStatement();
var_dump($voidResult); // NULL返回值类型声明
php
<?php
declare(strict_types=1);
// 标量类型返回值
function double(int $value): int
{
return $value * 2;
}
// 可空返回值
function findUserName(?int $userId): ?string
{
if ($userId === null) {
return null;
}
// 模拟查找
return "User #{$userId}";
}
echo findUserName(1) . "\n"; // User #1
var_dump(findUserName(null)); // NULL
// 联合类型返回值(PHP 8.0+)
function parseValue(string $input): int|string|float
{
if (is_numeric($input)) {
if (str_contains($input, '.')) {
return (float) $input;
}
return (int) $input;
}
return $input;
}
echo gettype(parseValue('42')) . "\n"; // integer
echo gettype(parseValue('3.14')) . "\n"; // double
echo gettype(parseValue('hello')) . "\n"; // string多返回值
PHP 函数只能返回一个值,但可以通过返回数组或对象来模拟多返回值。
php
<?php
declare(strict_types=1);
// 使用数组返回多个值
function divide(int $numerator, int $divisor): array
{
if ($divisor === 0) {
return ['result' => 0, 'remainder' => $numerator, 'error' => true];
}
return [
'result' => intdiv($numerator, $divisor),
'remainder' => $numerator % $divisor,
'error' => false,
];
}
$division = divide(17, 5);
echo "商: {$division['result']}, 余数: {$division['remainder']}\n";
// 商: 3, 余数: 2
// 使用 list 解构返回值
function getMinMax(array $numbers): array
{
return ['min' => min($numbers), 'max' => max($numbers)];
}
['min' => $min, 'max' => $max] = getMinMax([3, 7, 1, 9, 4]);
echo "最小值: {$min}, 最大值: {$max}\n";
// 最小值: 1, 最大值: 9
// 使用枚举+匹配返回结果(PHP 8.1+)
function parseJson(string $json): array
{
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return ['status' => 'error', 'message' => json_last_error_msg()];
}
return ['status' => 'success', 'data' => $data];
}void 返回类型
void 返回类型表示函数不返回有意义的值。声明了 void 的函数可以省略 return 语句,或使用空的 return; 终止执行。
php
<?php
declare(strict_types=1);
// void 返回类型
function logToFile(string $message): void
{
$timestamp = date('Y-m-d H:i:s');
$line = "[{$timestamp}] {$message}\n";
// 写入文件(省略实际文件操作)
echo $line;
}
logToFile('Application started');
// void 函数中的 return 用于提前退出
function validateAge(int $age): void
{
if ($age < 0) {
echo "年龄不能为负数\n";
return;
}
if ($age > 150) {
echo "年龄值不合理\n";
return;
}
echo "年龄验证通过: {$age}\n";
}
validateAge(25); // 年龄验证通过: 25
validateAge(-5); // 年龄不能为负数
validateAge(200); // 年龄值不合理void 类型限制
声明了 void 返回类型的函数不能返回任何值。return;(无返回值)是允许的,但 return null; 或 return $value; 会导致 TypeError。
never 返回类型(PHP 8.1+)
never 返回类型表示函数永远不会正常返回。这类函数要么抛出异常,要么调用 exit()/die() 终止程序。
php
<?php
declare(strict_types=1);
// 始终抛出异常
function throwIfEmpty(?string $value, string $name): string
{
if ($value === null || $value === '') {
throw new InvalidArgumentException("{$name} cannot be empty");
}
return $value;
}
try {
throwIfEmpty('', 'username');
} catch (InvalidArgumentException $e) {
echo $e->getMessage() . "\n"; // username cannot be empty
}
// 使用 never 标记始终终止的函数
function redirect(string $url): never
{
header("Location: {$url}");
exit;
}
function abort(int $code, string $message = ''): never
{
http_response_code($code);
echo json_encode(['error' => $message], JSON_UNESCAPED_UNICODE);
exit;
}
// 编译器会在 never 函数后检测到不可达代码
function processRequest(string $action): string
{
if ($action === 'redirect') {
redirect('/home'); // never 函数调用
// 以下代码不可达,PHP 会发出警告
// return '';
}
if ($action === 'abort') {
abort(404, 'Not found'); // never 函数调用
}
return "Action: {$action}";
}never vs void
void:函数正常执行完毕,但不返回有意义的值never:函数永远不会正常返回(总是异常退出或终止)
详细说明
返回类型与严格模式
在严格模式下,返回值必须精确匹配声明的类型(或为其子类型),PHP 不会进行隐式类型转换。
php
<?php
declare(strict_types=1);
// 严格模式:返回值类型必须精确匹配
function getInt(): int
{
return 42; // OK
// return 42.0; // TypeError: Return value must be of type int, float given
// return '42'; // TypeError: Return value must be of type int, string given
}
function getFloat(): float
{
return 3.14; // OK
return 42; // OK: int 是 float 的子类型
// return '3.14'; // TypeError
}
function getString(): string
{
return 'hello'; // OK
// return 42; // TypeError
}协变返回类型
子类方法的返回类型可以比父类更具体(更窄),这是类型系统的协变规则。
php
<?php
declare(strict_types=1);
interface RepositoryInterface
{
public function findById(int $id): ?object;
}
class UserRepository implements RepositoryInterface
{
public function findById(int $id): ?User
{
// 返回值类型更具体:User 是 object 的子类
if ($id === 1) {
return new User('Alice');
}
return null;
}
}
class User
{
public function __construct(public readonly string $name) {}
}
$repo = new UserRepository();
$user = $repo->findById(1);
if ($user !== null) {
echo $user->name . "\n"; // Alice
}条件返回与提前退出
良好的函数设计通常遵循"提前退出"模式,先处理错误和边界情况,再处理正常逻辑。
php
<?php
declare(strict_types=1);
// 推荐:提前退出模式
function calculatePrice(int $quantity, float $unitPrice, int $discountPercent = 0): float
{
if ($quantity <= 0) {
return 0.0;
}
if ($unitPrice < 0) {
throw new InvalidArgumentException('Unit price cannot be negative');
}
if ($discountPercent < 0 || $discountPercent > 100) {
throw new InvalidArgumentException('Discount must be between 0 and 100');
}
$subtotal = $quantity * $unitPrice;
$discount = $subtotal * ($discountPercent / 100);
return round($subtotal - $discount, 2);
}
echo calculatePrice(10, 99.9, 10) . "\n"; // 899.1实战示例
Result 模式处理错误
php
<?php
declare(strict_types=1);
// 使用类封装返回结果(避免异常的性能开销)
final class Result
{
private function __construct(
private readonly bool $success,
private readonly mixed $value = null,
private readonly ?string $error = null
) {}
public static function ok(mixed $value): self
{
return new self(true, $value);
}
public static function fail(string $error): self
{
return new self(false, null, $error);
}
public function isSuccess(): bool
{
return $this->success;
}
public function getValue(): mixed
{
return $this->value;
}
public function getError(): ?string
{
return $this->error;
}
public function unwrap(): mixed
{
if (!$this->success) {
throw new RuntimeException($this->error ?? 'Unknown error');
}
return $this->value;
}
}
function divideSafely(int $a, int $b): Result
{
if ($b === 0) {
return Result::fail('Division by zero');
}
return Result::ok($a / $b);
}
// 使用示例
$result = divideSafely(10, 3);
if ($result->isSuccess()) {
echo "结果: " . $result->getValue() . "\n";
} else {
echo "错误: " . $result->getError() . "\n";
}
$errorResult = divideSafely(10, 0);
echo $errorResult->isSuccess() ? 'ok' : 'error'; // error生成器与返回值
php
<?php
declare(strict_types=1);
// 使用 Generator 返回序列
function fibonacciSequence(int $limit): Generator
{
$a = 0;
$b = 1;
for ($i = 0; $i < $limit; $i++) {
yield $a;
[$a, $b] = [$b, $a + $b];
}
}
foreach (fibonacciSequence(10) as $index => $number) {
echo "F({$index}) = {$number}\n";
}
// F(0) = 0, F(1) = 1, F(2) = 1, F(3) = 2, ...注意事项
常见陷阱
- 忘记 return 语句
php
<?php
declare(strict_types=1);
// 常见错误:所有分支都有返回,但函数末尾缺少 return
function getStatus(int $score): string
{
if ($score >= 90) {
return 'A';
} elseif ($score >= 60) {
return 'B';
}
// 缺少 return 'C',将返回 null,导致类型错误
}
// 修复:确保所有路径都有返回值
function getStatusFixed(int $score): string
{
if ($score >= 90) {
return 'A';
} elseif ($score >= 60) {
return 'B';
}
return 'C'; // 默认返回值
}- void 函数返回值
php
<?php
declare(strict_types=1);
// 错误:void 函数不能返回值
function wrongVoid(): void
{
return 42; // TypeError
}
// 正确:void 函数只能 return; 或无 return
function correctVoid(): void
{
echo "Done\n";
return; // 允许空 return
}- nullable 返回值与空值判断
php
<?php
declare(strict_types=1);
function findEmail(int $userId): ?string
{
// 可能返回 null
$emails = [1 => 'alice@example.com', 2 => 'bob@example.com'];
return $emails[$userId] ?? null;
}
// 安全使用可空返回值
$email = findEmail(1);
if ($email !== null) {
echo strlen($email) . "\n";
}
// PHP 8.0+ nullsafe 操作符
echo strlen(findEmail(1) ?? '') . "\n";
echo strlen(findEmail(999) ?? '') . "\n"; // 不报错最佳实践
1. 始终声明返回类型
php
<?php
declare(strict_types=1);
// 不推荐
function calculate($a, $b)
{
return $a + $b;
}
// 推荐
function calculate(int $a, int $b): int
{
return $a + $b;
}2. 保持返回值一致性
php
<?php
declare(strict_types=1);
// 不推荐:一个函数返回多种不同含义的值
function processData($input)
{
if (is_string($input)) {
return strlen($input);
}
if (is_array($input)) {
return count($input);
}
return false;
}
// 推荐:使用不同的函数或返回统一的类型
function getStringLength(string $input): int
{
return strlen($input);
}
function getArrayCount(array $input): int
{
return count($input);
}3. 使用 never 标记终止函数
php
<?php
declare(strict_types=1);
// 对于总是终止执行的函数,使用 never 类型
function handle404(): never
{
http_response_code(404);
include __DIR__ . '/404.php';
exit;
}
function ensureLoggedIn(): void
{
if (!isset($_SESSION['user'])) {
redirect('/login'); // 如果 redirect 返回 never,这里后续代码不可达
}
}