Skip to content

返回值

概述

返回值是函数将处理结果传递给调用者的方式。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.0int, float, string, bool
arrayPHP 7.0返回数组
callablePHP 7.0返回可调用结构
selfPHP 7.0返回当前类的实例
?T (nullable)PHP 7.1返回指定类型或 null
voidPHP 7.1无返回值或返回 null
objectPHP 7.2返回任意对象
iterablePHP 7.1返回数组或 Traversable
staticPHP 8.0延迟静态绑定返回
T1|T2 (联合)PHP 8.0返回多种类型之一
T&U (交叉)PHP 8.1返回同时满足多个接口的对象
neverPHP 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, ...

注意事项

常见陷阱

  1. 忘记 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'; // 默认返回值
}
  1. 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
}
  1. 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,这里后续代码不可达
    }
}

参考链接