您好!欢迎访问家园网-www.jy.wang!

家园网

请讲解PHP的try-catch结构的语法和运行逻辑,并进行简单示例和复杂示例

网络 作者:本站 点击:

PHP的try-catch结构简明教程

基本语法

try {
    // 可能出错的代码
} catch (Exception $e) {
    // 出错时执行的代码
} finally {
    // 无论是否出错都会执行的代码(可选)
}

运行逻辑

  1. try块‌:程序先执行try中的代码

  2. 正常情况‌:如果try中的代码全部执行成功,跳过catch块

  3. 异常情况‌:如果try中抛出异常,立即停止try块执行,跳转到匹配的catch块

  4. finally块‌:无论是否发生异常,最后都会执行finally中的代码

简单示例

示例1:基本用法

try {
    $result = 10 / 0; // 这里会抛出除零错误
    echo "结果: ".$result;
} catch (DivisionByZeroError $e) {
    echo "出错了: ".$e->getMessage(); // 输出错误信息
} finally {
    echo "<br>计算结束"; // 无论是否出错都会执行
}

示例2:文件操作

try {
    $file = fopen("不存在的文件.txt", "r");
    if (!$file) {
        throw new Exception("无法打开文件"); // 手动抛出异常
    }
    // 读取文件内容...
} catch (Exception $e) {
    echo "文件操作错误: ".$e->getMessage();
} finally {
    if (isset($file) && $file) {
        fclose($file); // 确保文件资源被释放
    }
}

示例3:数据库操作

try {
    $pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass");
    $stmt = $pdo->query("SELECT * FROM 不存在的表");
    $results = $stmt->fetchAll();
} catch (PDOException $e) {
    echo "数据库错误: ".$e->getMessage();
} finally {
    $pdo = null; // 关闭数据库连接
}

关键点总结

  1. try‌:包裹可能出错的代码

  2. catch‌:捕获特定类型的异常(可以多个catch块)

  3. finally‌:清理资源的理想位置

  4. $e->getMessage()‌:获取错误信息

  5. 可以手动用throw new Exception()抛出异常

这种结构让错误处理更加优雅,避免了代码被大量if-else判断语句污染。


复杂示例

以下是一个完整的数据库事务处理系统示例,展示多层try-catch、自定义异常和事务回滚:

实现了完整的银行转账事务处理流程

  1. 包含多层try-catch嵌套结构

  2. 使用自定义异常类区分业务异常和系统异常

  3. 数据库事务确保数据一致性

  4. 完善的错误处理和资源清理机制

  5. 输入验证与业务逻辑分离

  6. 支持事务回滚和错误日志记录

<?php
class DatabaseException extends Exception {}
class ValidationException extends Exception {}
class TransactionSystem {
    private $pdo;
    
    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }
    
    public function transferFunds($fromAccount, $toAccount, $amount) {
        try {
            // 开启事务
            $this->pdo->beginTransaction();
            
            // 验证输入
            $this->validateInput($fromAccount, $toAccount, $amount);
            
            // 检查账户余额
            $this->checkBalance($fromAccount, $amount);
            
            // 执行转账
            $this->executeTransfer($fromAccount, $toAccount, $amount);
            
            // 记录交易日志
            $this->logTransaction($fromAccount, $toAccount, $amount);
            
            // 提交事务
            $this->pdo->commit();
            
            return "转账成功: {$amount}元 从 {$fromAccount} 到 {$toAccount}";
            
        } catch (ValidationException $e) {
            // 输入验证错误,无需回滚
            return "验证错误: " . $e->getMessage();
            
        } catch (DatabaseException $e) {
            // 数据库错误,回滚事务
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            return "数据库错误: " . $e->getMessage();
            
        } catch (Exception $e) {
            // 其他未知错误,回滚事务
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            error_log("未知错误: " . $e->getMessage());
            return "系统错误,请稍后再试";
            
        } finally {
            // 清理资源
            $this->cleanup();
        }
    }
    
    private function validateInput($from, $to, $amount) {
        if (!is_numeric($amount) || $amount <= 0) {
            throw new ValidationException("金额必须为正数");
        }
        if ($from === $to) {
            throw new ValidationException("不能转账给自己");
        }
    }
    
    private function checkBalance($account, $amount) {
        try {
            $stmt = $this->pdo->prepare("SELECT balance FROM accounts WHERE id = ?");
            $stmt->execute([$account]);
            $balance = $stmt->fetchColumn();
            
            if ($balance < $amount) {
                throw new ValidationException("账户余额不足");
            }
        } catch (PDOException $e) {
            throw new DatabaseException("查询余额失败: " . $e->getMessage());
        }
    }
    
    private function executeTransfer($from, $to, $amount) {
        try {
            // 扣除转出账户金额
            $stmt = $this->pdo->prepare(
                "UPDATE accounts SET balance = balance - ? WHERE id = ?"
            );
            $stmt->execute([$amount, $from]);
            
            // 增加转入账户金额
            $stmt = $this->pdo->prepare(
                "UPDATE accounts SET balance = balance + ? WHERE id = ?"
            );
            $stmt->execute([$amount, $to]);
        } catch (PDOException $e) {
            throw new DatabaseException("转账操作失败: " . $e->getMessage());
        }
    }
    
    private function logTransaction($from, $to, $amount) {
        try {
            $stmt = $this->pdo->prepare(
                "INSERT INTO transactions (from_account, to_account, amount) VALUES (?, ?, ?)"
            );
            $stmt->execute([$from, $to, $amount]);
        } catch (PDOException $e) {
            throw new DatabaseException("交易记录失败: " . $e->getMessage());
        }
    }
    
    private function cleanup() {
        // 关闭数据库连接等清理操作
    }
}
// 使用示例
try {
    $pdo = new PDO('mysql:host=localhost;dbname=bank', 'user', 'pass');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $system = new TransactionSystem($pdo);
    echo $system->transferFunds('A1001', 'B2002', 500);
    
} catch (PDOException $e) {
    echo "数据库连接失败: " . $e->getMessage();
}
?>




标签: