返回值

函数的返回值是函数执行完成后向外传递结果的方式。理解返回值的概念和用法,能够让我们编写出更强大、更灵活的函数。

返回值的基本概念

什么是返回值?

返回值是函数执行后向调用者返回的结果。它就像是函数的"输出接口",让函数能够将处理结果传递给其他代码继续使用。

<?php
// 简单的返回值示例
function addNumbers($a, $b) {
    $sum = $a + $b;
    return $sum;  // 返回计算结果
}

$result = addNumbers(5, 3);  // 接收返回值
echo "5 + 3 = $result";  // 输出:5 + 3 = 8
?>

return 语句的作用

return 语句有两个主要作用:

  1. 返回值:将结果传递给调用者
  2. 终止函数:立即结束函数执行
<?php
function checkNumber($number) {
    if ($number > 0) {
        return "正数";  // 返回并终止函数
    } elseif ($number < 0) {
        return "负数";  // 返回并终止函数
    } else {
        return "零";    // 返回并终止函数
    }

    // 这行代码永远不会执行,因为前面已经有return语句
    echo "这句话不会显示";
}

echo checkNumber(10);  // 输出:正数
echo checkNumber(-5);  // 输出:负数
echo checkNumber(0);   // 输出:零
?>

基本返回值类型

返回简单数据类型

<?php
// 返回整数
function getAge() {
    return 25;
}

// 返回浮点数
function getPrice() {
    return 99.99;
}

// 返回字符串
function getUserName() {
    return "张三";
}

// 返回布尔值
function isAdmin() {
    return true;
}

// 返回数组
function getUserInfo() {
    return [
        'name' => '李四',
        'age' => 30,
        'email' => 'lisi@example.com'
    ];
}

// 使用各种返回值
echo "年龄:" . getAge() . "<br>";
echo "价格:" . getPrice() . "<br>";
echo "用户名:" . getUserName() . "<br>";
echo "是否管理员:" . (isAdmin() ? "是" : "否") . "<br>";

$userInfo = getUserInfo();
echo "用户信息:{$userInfo['name']}, {$userInfo['age']}岁<br>";
?>

返回 null

<?php
function findUserById($userId) {
    $users = [
        1 => '张三',
        2 => '李四',
        3 => '王五'
    ];

    if (isset($users[$userId])) {
        return $users[$userId];  // 找到用户,返回用户名
    } else {
        return null;  // 没找到用户,返回null
    }
}

$user1 = findUserById(1);
if ($user1 !== null) {
    echo "找到用户:$user1<br>";
} else {
    echo "用户不存在<br>";
}

$user2 = findUserById(99);
if ($user2 !== null) {
    echo "找到用户:$user2<br>";
} else {
    echo "用户不存在<br>";
}
?>

返回值类型声明

PHP 7.0+ 支持返回值类型声明,可以指定函数应该返回什么类型的数据。

基本类型声明

<?php
// 声明返回整数
function calculateSum(int $a, int $b): int {
    return $a + $b;
}

// 声明返回字符串
function formatName(string $firstName, string $lastName): string {
    return $firstName . ' ' . $lastName;
}

// 声明返回浮点数
function calculateAverage(array $numbers): float {
    return array_sum($numbers) / count($numbers);
}

// 声明返回布尔值
function isValidEmail(string $email): bool {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

// 声明返回数组
function getEvenNumbers(int $limit): array {
    $evenNumbers = [];
    for ($i = 2; $i <= $limit; $i += 2) {
        $evenNumbers[] = $i;
    }
    return $evenNumbers;
}

// 测试类型声明的函数
echo "5 + 3 = " . calculateSum(5, 3) . "<br>";
echo "姓名:" . formatName("张", "三") . "<br>";
echo "平均值:" . calculateAverage([1, 2, 3, 4, 5]) . "<br>";
echo "邮箱是否有效:" . (isValidEmail("test@example.com") ? "是" : "否") . "<br>";
echo "偶数:" . implode(', ', getEvenNumbers(10)) . "<br>";
?>

可空返回类型

<?php
// 返回字符串或null
function findUserName(int $userId): ?string {
    $users = [
        1 => '张三',
        2 => '李四'
    ];

    return $users[$userId] ?? null;
}

// 返回数组或null
function getUserSettings(int $userId): ?array {
    $settings = [
        1 => ['theme' => 'light', 'notifications' => true],
        2 => ['theme' => 'dark', 'notifications' => false]
    ];

    return $settings[$userId] ?? null;
}

// 使用可空返回类型
$userName = findUserName(1);
echo "用户1姓名:" . ($userName ?? "不存在") . "<br>";

$userName = findUserName(99);
echo "用户99姓名:" . ($userName ?? "不存在") . "<br>";

$settings = getUserSettings(1);
if ($settings !== null) {
    echo "用户1设置:主题={$settings['theme']}, 通知=" . ($settings['notifications'] ? "开启" : "关闭") . "<br>";
}
?>

联合返回类型(PHP 8.0+)

<?php
// 返回字符串或整数
function processData($data): string|int {
    if (is_numeric($data)) {
        return (int)$data;
    } else {
        return (string)$data;
    }
}

// 返回数组或字符串
function getConfig(string $key): array|string {
    $configs = [
        'database' => ['host' => 'localhost', 'port' => 3306],
        'version' => '1.0.0'
    ];

    return $configs[$key] ?? "配置不存在";
}

// 测试联合类型
echo processData(123) . "<br>";    // 输出:123 (整数)
echo processData("hello") . "<br>"; // 输出:hello (字符串)

$dbConfig = getConfig('database');
if (is_array($dbConfig)) {
    echo "数据库配置:{$dbConfig['host']}:{$dbConfig['port']}<br>";
}

echo "版本:" . getConfig('version') . "<br>";
?>

多返回值处理

PHP函数本身只能返回一个值,但我们可以通过数组、对象等方式实现多返回值的效果。

使用数组返回多个值

<?php
// 返回用户信息数组
function getUserDetails(int $userId): array {
    // 模拟数据库查询
    $users = [
        1 => [
            'name' => '张三',
            'age' => 25,
            'email' => 'zhangsan@example.com',
            'is_active' => true
        ]
    ];

    $user = $users[$userId] ?? null;

    if ($user === null) {
        return ['success' => false, 'message' => '用户不存在'];
    }

    return [
        'success' => true,
        'data' => $user
    ];
}

// 使用列表结构提取返回值
function getStudentStats(int $studentId): array {
    // 模拟学生数据
    $students = [
        1 => ['chinese' => 85, 'math' => 92, 'english' => 88]
    ];

    $scores = $students[$studentId] ?? [0, 0, 0];
    $total = $scores['chinese'] + $scores['math'] + $scores['english'];
    $average = $total / 3;

    return [$total, $average, $scores];  // 返回多个值
}

// 提取多个返回值
[$totalScore, $averageScore, $subjectScores] = getStudentStats(1);

echo "总分:$totalScore<br>";
echo "平均分:" . round($averageScore, 2) . "<br>";
echo "各科成绩:语文{$subjectScores['chinese']}, 数学{$subjectScores['math']}, 英语{$subjectScores['english']}<br>";

// 更复杂的示例:计算器函数
function advancedCalculator(float $a, float $b, string $operation): array {
    $results = [];

    switch ($operation) {
        case '+':
            $results['sum'] = $a + $b;
            break;
        case '-':
            $results['difference'] = $a - $b;
            break;
        case '*':
            $results['product'] = $a * $b;
            break;
        case '/':
            if ($b != 0) {
                $results['quotient'] = $a / $b;
                $results['remainder'] = $a % $b;
            } else {
                $results['error'] = '除数不能为零';
            }
            break;
        default:
            $results['error'] = '不支持的操作';
    }

    $results['operation'] = "$a $operation $b";
    $results['timestamp'] = date('Y-m-d H:i:s');

    return $results;
}

// 使用多返回值计算器
$calcResult = advancedCalculator(10, 3, '/');
foreach ($calcResult as $key => $value) {
    echo "$key: $value<br>";
}
?>

使用对象返回多个值

<?php
// 定义结果对象
class OperationResult {
    public $success;
    public $data;
    public $message;
    public $timestamp;

    public function __construct($success, $data = null, $message = '') {
        $this->success = $success;
        $this->data = $data;
        $this->message = $message;
        $this->timestamp = date('Y-m-d H:i:s');
    }
}

// 用户管理类
class UserManager {
    public function authenticateUser(string $username, string $password): OperationResult {
        // 模拟用户数据库
        $users = [
            'admin' => ['password' => 'admin123', 'role' => 'admin', 'id' => 1],
            'user' => ['password' => 'user123', 'role' => 'user', 'id' => 2]
        ];

        if (!isset($users[$username])) {
            return new OperationResult(false, null, '用户名不存在');
        }

        $user = $users[$username];
        if ($user['password'] !== $password) {
            return new OperationResult(false, null, '密码错误');
        }

        // 认证成功,返回用户信息(不含密码)
        $userData = [
            'id' => $user['id'],
            'username' => $username,
            'role' => $user['role']
        ];

        return new OperationResult(true, $userData, '认证成功');
    }
}

// 使用对象返回值
$userManager = new UserManager();
$authResult = $userManager->authenticateUser('admin', 'admin123');

if ($authResult->success) {
    echo "登录成功!用户信息:<br>";
    echo "ID: {$authResult->data['id']}<br>";
    echo "用户名: {$authResult->data['username']}<br>";
    echo "角色: {$authResult->data['role']}<br>";
    echo "时间: {$authResult->timestamp}<br>";
} else {
    echo "登录失败:" . $authResult->message . "<br>";
}
?>

早期返回模式

早期返回(Early Return)是一种编程模式,通过在函数早期处理错误情况或简单情况,使代码更清晰。

复杂的条件处理

<?php
// 不好的做法:深层嵌套
function processOrderBad($order) {
    if ($order !== null) {
        if (isset($order['items']) && !empty($order['items'])) {
            if (isset($order['customer']) && !empty($order['customer'])) {
                if ($order['total'] > 0) {
                    // 处理订单逻辑
                    return "订单处理成功";
                } else {
                    return "订单金额必须大于0";
                }
            } else {
                return "缺少客户信息";
            }
        } else {
            return "订单中没有商品";
        }
    } else {
        return "订单数据为空";
    }
}

// 好的做法:早期返回
function processOrder($order): string {
    // 早期检查错误情况
    if ($order === null) {
        return "订单数据为空";
    }

    if (!isset($order['items']) || empty($order['items'])) {
        return "订单中没有商品";
    }

    if (!isset($order['customer']) || empty($order['customer'])) {
        return "缺少客户信息";
    }

    if ($order['total'] <= 0) {
        return "订单金额必须大于0";
    }

    // 主要逻辑
    return "订单处理成功";
}

// 测试
$testOrder = [
    'items' => ['商品1', '商品2'],
    'customer' => ['name' => '张三'],
    'total' => 100
];

echo processOrder($testOrder) . "<br>";
echo processOrder(null) . "<br>";
?>

参数验证的早期返回

<?php
// 注册用户函数 - 使用早期返回验证
function registerUser($userData): array {
    // 验证必填字段
    if (!isset($userData['username']) || empty(trim($userData['username']))) {
        return ['success' => false, 'message' => '用户名不能为空'];
    }

    if (!isset($userData['email']) || empty(trim($userData['email']))) {
        return ['success' => false, 'message' => '邮箱不能为空'];
    }

    if (!isset($userData['password']) || strlen($userData['password']) < 6) {
        return ['success' => false, 'message' => '密码至少6个字符'];
    }

    // 验证邮箱格式
    if (!filter_var($userData['email'], FILTER_VALIDATE_EMAIL)) {
        return ['success' => false, 'message' => '邮箱格式不正确'];
    }

    // 验证用户名长度
    if (strlen($userData['username']) < 3 || strlen($userData['username']) > 20) {
        return ['success' => false, 'message' => '用户名必须在3-20个字符之间'];
    }

    // 所有验证通过,开始注册流程
    $user = [
        'id' => uniqid(),
        'username' => $userData['username'],
        'email' => $userData['email'],
        'password_hash' => password_hash($userData['password'], PASSWORD_DEFAULT),
        'created_at' => date('Y-m-d H:i:s'),
        'status' => 'active'
    ];

    // 模拟保存到数据库
    saveUser($user);

    return [
        'success' => true,
        'message' => '注册成功',
        'user_id' => $user['id']
    ];
}

function saveUser($user) {
    // 模拟保存操作
    return true;
}

// 测试注册
$testUsers = [
    ['username' => 'test', 'email' => 'test@example.com', 'password' => 'password123'],
    ['username' => '', 'email' => 'test@example.com', 'password' => 'password123'],
    ['username' => 'test', 'email' => 'invalid-email', 'password' => 'password123']
];

foreach ($testUsers as $userData) {
    $result = registerUser($userData);
    echo $result['message'] . "<br>";
}
?>

返回值 vs 引用传递

有时候我们可以选择返回值或引用传递来修改数据。理解两者的区别很重要。

返回修改后的副本

<?php
// 返回修改后的数组副本
function addTaxToPrices(array $prices, float $taxRate): array {
    $pricesWithTax = [];
    foreach ($prices as $price) {
        $pricesWithTax[] = $price * (1 + $taxRate);
    }
    return $pricesWithTax;
}

// 原数组不会被修改
$originalPrices = [100, 200, 300];
$taxedPrices = addTaxToPrices($originalPrices, 0.1);

echo "原价格:" . implode(', ', $originalPrices) . "<br>";
echo "含税价格:" . implode(', ', $taxedPrices) . "<br>";
?>

使用引用传递修改原数据

<?php
// 通过引用传递修改原数组
function addTaxToPricesRef(array &$prices, float $taxRate): void {
    foreach ($prices as &$price) {
        $price = $price * (1 + $taxRate);
    }
    // 不需要返回值,因为原数组已经被修改
}

// 原数组会被修改
$prices = [100, 200, 300];
echo "修改前:" . implode(', ', $prices) . "<br>";

addTaxToPricesRef($prices, 0.1);
echo "修改后:" . implode(', ', $prices) . "<br>";
?>

链式调用(返回$this)

在面向对象编程中,返回$this可以实现方法链式调用。

<?php
class QueryBuilder {
    private $query = '';
    private $params = [];

    public function select(string $columns): self {
        $this->query = "SELECT $columns";
        return $this;  // 返回自身以支持链式调用
    }

    public function from(string $table): self {
        $this->query .= " FROM $table";
        return $this;
    }

    public function where(string $condition, $value): self {
        $this->query .= " WHERE $condition";
        $this->params[] = $value;
        return $this;
    }

    public function orderBy(string $column, string $direction = 'ASC'): self {
        $this->query .= " ORDER BY $column $direction";
        return $this;
    }

    public function getQuery(): string {
        return $this->query;
    }

    public function getParams(): array {
        return $this->params;
    }
}

// 使用链式调用
$queryBuilder = new QueryBuilder();
$query = $queryBuilder
    ->select('name, email, age')
    ->from('users')
    ->where('age > ?', 18)
    ->orderBy('name', 'ASC')
    ->getQuery();

echo "生成的SQL查询:$query<br>";
?>

异常处理与返回值

使用异常 vs 返回错误码

<?php
// 方式1:返回错误码/错误信息
function divideWithReturn($a, $b) {
    if ($b == 0) {
        return ['success' => false, 'message' => '除数不能为零'];
    }
    return ['success' => true, 'result' => $a / $b];
}

// 方式2:抛出异常
function divideWithException($a, $b) {
    if ($b == 0) {
        throw new InvalidArgumentException('除数不能为零');
    }
    return $a / $b;
}

// 使用返回错误码的方式
$result1 = divideWithReturn(10, 2);
if ($result1['success']) {
    echo "结果:" . $result1['result'] . "<br>";
} else {
    echo "错误:" . $result1['message'] . "<br>";
}

// 使用异常的方式
try {
    $result2 = divideWithException(10, 0);
    echo "结果:$result2<br>";
} catch (InvalidArgumentException $e) {
    echo "错误:" . $e->getMessage() . "<br>";
}
?>

自定义异常类

<?php
// 自定义异常类
class ValidationException extends Exception {
    private $errors;

    public function __construct(array $errors, string $message = "数据验证失败") {
        parent::__construct($message);
        $this->errors = $errors;
    }

    public function getErrors(): array {
        return $this->errors;
    }
}

class UserRegistrationService {
    public function registerUser($userData): array {
        $this->validateUserData($userData);

        // 如果验证通过,继续注册流程
        $userId = $this->saveUser($userData);

        return [
            'success' => true,
            'user_id' => $userId,
            'message' => '注册成功'
        ];
    }

    private function validateUserData($userData): void {
        $errors = [];

        if (empty($userData['username'])) {
            $errors[] = '用户名不能为空';
        }

        if (empty($userData['email'])) {
            $errors[] = '邮箱不能为空';
        }

        if (!filter_var($userData['email'], FILTER_VALIDATE_EMAIL)) {
            $errors[] = '邮箱格式不正确';
        }

        if (!empty($errors)) {
            throw new ValidationException($errors);
        }
    }

    private function saveUser($userData): string {
        // 模拟保存用户
        return uniqid('user_');
    }
}

// 使用自定义异常
$registrationService = new UserRegistrationService();

try {
    $result = $registrationService->registerUser([
        'username' => 'testuser',
        'email' => 'invalid-email'
    ]);
    echo $result['message'] . "<br>";
} catch (ValidationException $e) {
    echo $e->getMessage() . "<br>";
    echo "具体错误:<br>";
    foreach ($e->getErrors() as $error) {
        echo "- $error<br>";
    }
}
?>

实际应用示例

文件处理器

<?php
class FileProcessor {
    // 读取文件内容
    public function readFile(string $filePath): array {
        if (!file_exists($filePath)) {
            return [
                'success' => false,
                'message' => '文件不存在',
                'content' => null
            ];
        }

        if (!is_readable($filePath)) {
            return [
                'success' => false,
                'message' => '文件不可读',
                'content' => null
            ];
        }

        $content = file_get_contents($filePath);
        if ($content === false) {
            return [
                'success' => false,
                'message' => '读取文件失败',
                'content' => null
            ];
        }

        return [
            'success' => true,
            'message' => '文件读取成功',
            'content' => $content,
            'size' => filesize($filePath),
            'type' => mime_content_type($filePath)
        ];
    }

    // 写入文件内容
    public function writeFile(string $filePath, string $content): array {
        $directory = dirname($filePath);

        // 检查目录是否存在
        if (!is_dir($directory)) {
            if (!mkdir($directory, 0755, true)) {
                return [
                    'success' => false,
                    'message' => '无法创建目录',
                    'bytes_written' => 0
                ];
            }
        }

        // 写入文件
        $bytesWritten = file_put_contents($filePath, $content);

        if ($bytesWritten === false) {
            return [
                'success' => false,
                'message' => '写入文件失败',
                'bytes_written' => 0
            ];
        }

        return [
            'success' => true,
            'message' => '文件写入成功',
            'bytes_written' => $bytesWritten,
            'file_path' => $filePath
        ];
    }

    // 备份文件
    public function backupFile(string $filePath): array {
        $result = $this->readFile($filePath);

        if (!$result['success']) {
            return $result;
        }

        $backupPath = $filePath . '.backup.' . date('Y-m-d_H-i-s');
        return $this->writeFile($backupPath, $result['content']);
    }
}

// 使用文件处理器
$processor = new FileProcessor();

// 写入测试文件
$writeResult = $processor->writeFile('test/sample.txt', '这是一个测试文件内容');
echo "写入结果:" . ($writeResult['success'] ? '成功' : '失败') . "<br>";
if ($writeResult['success']) {
    echo "写入字节数:" . $writeResult['bytes_written'] . "<br>";
}

// 读取文件
$readResult = $processor->readFile('test/sample.txt');
echo "读取结果:" . ($readResult['success'] ? '成功' : '失败') . "<br>";
if ($readResult['success']) {
    echo "文件内容:" . $readResult['content'] . "<br>";
    echo "文件大小:" . $readResult['size'] . " 字节<br>";
    echo "文件类型:" . $readResult['type'] . "<br>";
}

// 备份文件
$backupResult = $processor->backupFile('test/sample.txt');
echo "备份结果:" . ($backupResult['success'] ? '成功' : '失败') . "<br>";
?>

数据分析器

<?php
class DataAnalyzer {
    // 分析数字数组
    public function analyzeNumbers(array $numbers): array {
        if (empty($numbers)) {
            return [
                'success' => false,
                'message' => '数据为空',
                'statistics' => null
            ];
        }

        // 验证所有元素都是数字
        foreach ($numbers as $number) {
            if (!is_numeric($number)) {
                return [
                    'success' => false,
                    'message' => '数据包含非数字元素',
                    'statistics' => null
                ];
            }
        }

        $numbers = array_map('floatval', $numbers);
        sort($numbers);
        $count = count($numbers);

        $statistics = [
            'count' => $count,
            'sum' => array_sum($numbers),
            'mean' => array_sum($numbers) / $count,
            'min' => min($numbers),
            'max' => max($numbers),
            'median' => $this->calculateMedian($numbers),
            'range' => max($numbers) - min($numbers),
            'variance' => $this->calculateVariance($numbers),
            'standard_deviation' => $this->calculateStandardDeviation($numbers)
        ];

        return [
            'success' => true,
            'message' => '分析完成',
            'statistics' => $statistics
        ];
    }

    // 计算中位数
    private function calculateMedian(array $sortedNumbers): float {
        $count = count($sortedNumbers);
        $middle = floor($count / 2);

        if ($count % 2 === 0) {
            return ($sortedNumbers[$middle - 1] + $sortedNumbers[$middle]) / 2;
        } else {
            return $sortedNumbers[$middle];
        }
    }

    // 计算方差
    private function calculateVariance(array $numbers): float {
        $mean = array_sum($numbers) / count($numbers);
        $squaredDiffs = array_map(function($num) use ($mean) {
            return pow($num - $mean, 2);
        }, $numbers);
        return array_sum($squaredDiffs) / count($numbers);
    }

    // 计算标准差
    private function calculateStandardDeviation(array $numbers): float {
        return sqrt($this->calculateVariance($numbers));
    }

    // 生成分析报告
    public function generateReport(array $numbers): string {
        $analysis = $this->analyzeNumbers($numbers);

        if (!$analysis['success']) {
            return "错误:" . $analysis['message'];
        }

        $stats = $analysis['statistics'];

        $report = "=== 数据分析报告 ===\n";
        $report .= "数据个数:{$stats['count']}\n";
        $report .= "总和:" . number_format($stats['sum'], 2) . "\n";
        $report .= "平均值:" . number_format($stats['mean'], 2) . "\n";
        $report .= "中位数:" . number_format($stats['median'], 2) . "\n";
        $report .= "最小值:" . number_format($stats['min'], 2) . "\n";
        $report .= "最大值:" . number_format($stats['max'], 2) . "\n";
        $report .= "极差:" . number_format($stats['range'], 2) . "\n";
        $report .= "方差:" . number_format($stats['variance'], 2) . "\n";
        $report .= "标准差:" . number_format($stats['standard_deviation'], 2) . "\n";
        $report .= "==================\n";

        return $report;
    }
}

// 使用数据分析器
$analyzer = new DataAnalyzer();

// 测试数据
$testData1 = [10, 20, 30, 40, 50];
$testData2 = [85, 92, 78, 65, 88, 95, 72, 58];
$testData3 = []; // 空数据
$testData4 = [10, 20, 'invalid', 30]; // 包含非数字

// 分析数据
$dataSets = [
    '数据集1' => $testData1,
    '数据集2' => $testData2,
    '空数据' => $testData3,
    '无效数据' => $testData4
];

foreach ($dataSets as $name => $data) {
    echo "<h4>$name</h4>";
    if (!empty($data)) {
        echo "数据:" . implode(', ', $data) . "<br>";
    }

    $result = $analyzer->analyzeNumbers($data);
    if ($result['success']) {
        $stats = $result['statistics'];
        echo "分析结果:<br>";
        echo "- 平均值:" . number_format($stats['mean'], 2) . "<br>";
        echo "- 标准差:" . number_format($stats['standard_deviation'], 2) . "<br>";
        echo "- 中位数:" . number_format($stats['median'], 2) . "<br>";
    } else {
        echo "错误:" . $result['message'] . "<br>";
    }
    echo "<br>";
}

// 生成完整报告
echo "<h4>完整分析报告</h4>";
echo "<pre>" . nl2br($analyzer->generateReport($testData2)) . "</pre>";
?>

最佳实践

1. 明确的返回值类型

<?php
// 好的做法:明确的返回值类型声明
function calculateDiscount(float $price, float $percentage): float {
    if ($percentage < 0 || $percentage > 100) {
        throw new InvalidArgumentException('折扣百分比必须在0-100之间');
    }
    return $price * (1 - $percentage / 100);
}

// 不好的做法:不明确的返回值
function calculateDiscountBad($price, $percentage) {
    // 可能返回整数、浮点数、字符串或null
    if ($price < 0) {
        return "价格不能为负数";
    }
    return $price * (1 - $percentage / 100);
}
?>

2. 一致的返回值格式

<?php
// 好的做法:一致的返回值格式
function apiResponse($data, string $message = '', bool $success = true): array {
    return [
        'success' => $success,
        'message' => $message,
        'data' => $data,
        'timestamp' => date('Y-m-d H:i:s')
    ];
}

// 使用一致的返回格式
function getUserData($userId): array {
    $user = findUserInDatabase($userId);
    if ($user) {
        return apiResponse($user, '获取用户数据成功');
    } else {
        return apiResponse(null, '用户不存在', false);
    }
}
?>

3. 避免混合返回类型

<?php
// 不好的做法:混合返回类型
function findUser($id) {
    if ($id == 1) {
        return ['name' => '张三'];  // 返回数组
    } elseif ($id == 2) {
        return "李四";              // 返回字符串
    } else {
        return false;               // 返回布尔值
    }
}

// 好的做法:统一的返回类型
function findUserFixed($id): ?array {
    $users = [
        1 => ['name' => '张三'],
        2 => ['name' => '李四']
    ];
    return $users[$id] ?? null;
}
?>

4. 使用适当的错误处理

<?php
// 对于可以预期的情况,返回错误信息
function validateEmail(string $email): array {
    if (empty($email)) {
        return ['valid' => false, 'error' => '邮箱不能为空'];
    }

    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return ['valid' => false, 'error' => '邮箱格式不正确'];
    }

    return ['valid' => true, 'error' => null];
}

// 对于意外情况,抛出异常
function connectToDatabase(string $host, string $username, string $password): PDO {
    try {
        return new PDO("mysql:host=$host", $username, $password);
    } catch (PDOException $e) {
        throw new RuntimeException("数据库连接失败: " . $e->getMessage());
    }
}
?>

常见错误和解决方案

1. 忘记返回值

<?php
// 错误:忘记返回值
function calculateTax($amount) {
    $tax = $amount * 0.1;
    // 忘记return $tax;
}

// 解决方案:确保有返回语句
function calculateTaxFixed($amount) {
    $tax = $amount * 0.1;
    return $tax;  // 添加return语句
}
?>

2. 返回值类型不匹配

<?php
// 声明返回字符串,但可能返回null
function getUserName(int $userId): string {
    $users = [1 => '张三'];
    return $users[$userId] ?? null;  // 可能返回null,违反类型声明
}

// 解决方案1:使用可空类型
function getUserNameFixed1(int $userId): ?string {
    $users = [1 => '张三'];
    return $users[$userId] ?? null;
}

// 解决方案2:提供默认值
function getUserNameFixed2(int $userId): string {
    $users = [1 => '张三'];
    return $users[$userId] ?? '未知用户';
}
?>

3. 过度使用返回值

<?php
// 不好的做法:函数做多件事还返回复杂结构
function processAndSaveAndNotify($data): array {
    // 处理数据
    $processed = processData($data);

    // 保存数据
    $saved = saveData($processed);

    // 发送通知
    $notified = sendNotification($saved);

    return [
        'processed' => $processed,
        'saved' => $saved,
        'notified' => $notified
    ];
}

// 好的做法:函数职责单一
function processData($data): array {
    // 只处理数据
    return $data;
}

function saveData($data): bool {
    // 只保存数据
    return true;
}

function sendNotification($data): bool {
    // 只发送通知
    return true;
}
?>

练习题

基础练习

  1. 简单计算函数

    <?php
    // 创建计算函数,返回不同运算的结果
    function calculate($a, $b, $operation) {
        // 返回运算结果
    }
    
    echo calculate(10, 5, '+');  // 应该输出:15
    echo calculate(10, 5, '-');  // 应该输出:5
    echo calculate(10, 5, '*');  // 应该输出:50
    ?>
    
  2. 数组处理函数

    <?php
    // 创建函数处理数组,返回统计信息
    function analyzeArray($numbers) {
        // 返回包含最大值、最小值、平均值、和的数组
    }
    
    $stats = analyzeArray([1, 5, 3, 9, 2]);
    print_r($stats);
    ?>
    
  3. 字符串验证函数

    <?php
    // 创建邮箱验证函数,返回验证结果和错误信息
    function validateEmail($email) {
        // 返回 ['valid' => bool, 'message' => string]
    }
    
    $result = validateEmail('test@example.com');
    print_r($result);
    ?>
    

进阶练习

  1. 用户认证系统

    <?php
    // 创建用户认证函数,包含登录验证和权限检查
    function authenticateUser($username, $password) {
        // 返回包含success、user_info、token、permissions的数组
    }
    
    $result = authenticateUser('admin', 'password123');
    print_r($result);
    ?>
    
  2. 文件操作类

    <?php
    class FileManager {
        public function readFile($filePath) {
            // 返回包含success、content、size、error的数组
        }
    
        public function writeFile($filePath, $content) {
            // 返回包含success、bytes_written、error的数组
        }
    }
    
    // 测试文件管理器
    ?>
    

实战练习

  1. 电商价格计算器

    <?php
    // 创建完整的电商价格计算器
    function calculateProductPrice($basePrice, $quantity, $discount = 0, $tax = 0.08) {
        // 返回详细的价格信息数组
    }
    
    $priceInfo = calculateProductPrice(100, 3, 10, 0.08);
    print_r($priceInfo);
    ?>
    
  2. 数据验证器

    <?php
    class DataValidator {
        public function validateUserData($userData) {
            // 验证用户数据,返回验证结果
        }
    
        public function validateProductData($productData) {
            // 验证商品数据,返回验证结果
        }
    }
    
    // 创建完整的数据验证系统
    ?>
    

总结

返回值是函数与外部世界沟通的重要桥梁。通过本章的学习,你应该能够:

  1. 理解return语句的作用和用法
  2. 掌握不同类型的返回值处理
  3. 使用返回值类型声明提高代码质量
  4. 实现多返回值的各种技巧
  5. 应用早期返回模式优化代码结构
  6. 选择合适的错误处理方式
  7. 在实际项目中遵循最佳实践

记住,好的返回值设计可以让函数更容易使用、测试和维护。在实际开发中,要始终考虑返回值的一致性、明确性和易用性。

下一章我们将学习变量作用域,了解函数内外变量的关系和访问规则。