Menu
CoddyTech

try、catch、finally

本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 68 课,共 91 课。

现在你已经知道如何创建和抛出异常,接下来需要学习如何捕获异常。try-catch-finally 结构可以让你妥善处理异常,而不是让它们导致应用程序崩溃。

将可能抛出异常的代码放在 try 块中,然后在 catch 块中处理异常:

<?php
class Calculator {
    public function divide(int $a, int $b): float {
        if ($b === 0) {
            throw new InvalidArgumentException("Cannot divide by zero");
        }
        return $a / $b;
    }
}

$calc = new Calculator();

try {
    echo $calc->divide(10, 0);
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
}

输出:

Error: Cannot divide by zero

你可以用多个 catch 块捕获不同类型的异常。PHP 会按顺序检查它们,所以要把更具体的异常放在前面:

<?php
try {
    // 可能出错的代码
} catch (InvalidArgumentException $e) {
    echo "Bad input: " . $e->getMessage();
} catch (Exception $e) {
    echo "Something went wrong: " . $e->getMessage();
}

无论是否抛出或捕获异常,finally 块都会运行。它非常适合执行清理任务,例如关闭连接:

<?php
try {
    echo "Attempting operation\n";
    throw new Exception("Failed");
} catch (Exception $e) {
    echo "Caught: " . $e->getMessage() . "\n";
} finally {
    echo "Cleanup complete";
}

输出:

Attempting operation
Caught: Failed
Cleanup complete

即使你在 try 或 catch 块中执行 return,finally 块也会执行,因此它适合用于必要的清理操作。

challenge icon

挑战

简单

我们来构建一个文件处理系统,演示如何结合使用 try-catch-finally 来妥善处理错误,同时确保始终执行清理操作。

你将把代码分布在三个文件中:

  • FileException.php:创建一个自定义的 FileException 类,使其继承 Exception。这个类用于表示系统中的文件相关错误。
  • FileProcessor.php:创建一个模拟文件操作的 FileProcessor 类。引入 FileException 文件。你的类应包含:
    • 一个私有布尔属性 $isOpen,初始值为 false
    • 一个 open(string $filename): void 方法,将 $isOpen 设置为 true,并打印 "Opening: [filename]"。如果文件名是 "invalid.txt",则抛出一个 FileException,错误消息为 "Cannot open file"
    • 一个 process(): void 方法,打印 "Processing file..."。如果 $isOpen 为 false,则抛出一个 RuntimeException,错误消息为 "File not open"
    • 一个 close(): void 方法,将 $isOpen 设置为 false,并打印 "File closed"
    • 一个 isOpen(): bool 方法,返回当前状态
  • main.php:引入 FileProcessor 文件。你将收到一个输入:文件名。

    创建一个 FileProcessor,并使用 try-catch-finally 结构来完成以下操作:

    • 在 try 代码块中:使用文件名调用 open(),然后调用 process()
    • 先捕获 FileException,并打印 "File error: [message]"
    • 捕获 RuntimeException,并打印 "Runtime error: [message]"
    • 在 finally 代码块中:使用 isOpen() 检查文件是否已打开,如果已打开,则调用 close()。然后打印 "Cleanup complete"

finally 代码块可确保无论操作成功还是失败,都会执行清理操作。这种模式对于管理文件、数据库连接或网络套接字等资源至关重要,因为无论处理过程中发生什么情况,都必须执行清理操作。

亲手试试

<?php
require_once 'FileProcessor.php';

// 读取输入
$filename = trim(fgets(STDIN));

// TODO:创建一个 FileProcessor 实例

// TODO:使用 try-catch-finally 结构:
// 在 try 块中:用文件名调用 open(),然后调用 process()
// 先捕获 FileException,并打印 "File error: [message]"
// 捕获 RuntimeException,并打印 "Runtime error: [message]"
// 在 finally 块中:用 isOpen() 检查文件是否已打开,如果已打开就调用 close()
//   然后打印 "Cleanup complete"

?>
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: PHP 在线编译器