Menu
CoddyTech

异常类

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

在 PHP 中,异常是用于表示程序运行过程中出现问题的对象。所有异常的基类都是 Exception,了解它的结构有助于你在面向对象编程应用中有效地处理错误。

抛出异常时,你会创建 Exception 类(或其子类)的一个实例,并附上描述出错原因的消息:

<?php
class BankAccount {
    public function __construct(private float $balance = 0) {}
    
    public function withdraw(float $amount): float {
        if ($amount > $this->balance) {
            throw new Exception("Insufficient funds");
        }
        $this->balance -= $amount;
        return $amount;
    }
}

$account = new BankAccount(100);
$account->withdraw(150);

这会产生一个未捕获的异常错误,错误消息为 "Insufficient funds"。

PHP 为不同情况提供了多个内置异常类。InvalidArgumentException 表示输入无效,RuntimeException 表示执行期间发生错误,LogicException 表示编程错误:

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

每个异常对象都包含有用的信息:getMessage() 返回错误消息,getCode() 返回可选的错误代码,getFile() 和 getLine() 会告诉你异常是在哪里抛出的。使用具体的异常类型可以让代码意图更清晰,也能更精确地处理错误。

challenge icon

挑战

简单

让我们构建一个库存管理系统,使用 PHP 内置的异常类来表示不同类型的问题。你将创建一个产品库存系统,其中的操作可能会以特定且有意义的方式失败。

你将把代码分成 3 个文件:

  • Product.php:创建一个 Product 类,用来表示库存中的商品。使用构造函数属性提升,定义一个 public $sku(string)、一个 public $name(string)和一个 private $quantity(int)。你的类应包含:
    • 一个方法 getQuantity(): int,用于返回当前数量
    • 一个方法 addStock(int $amount): void,用于增加数量。如果数量小于 1,则抛出 InvalidArgumentException 异常,错误消息为 "Amount must be positive"
    • 一个方法 removeStock(int $amount): void,用于减少数量。如果数量小于 1,则抛出 InvalidArgumentException 异常,错误消息为 "Amount must be positive"。如果数量超过当前数量,则抛出 RuntimeException 异常,错误消息为 "Insufficient stock"
  • Inventory.php:创建一个 Inventory 类,用于管理一组商品。引入 Product 文件。你的类应包含:
    • 一个 private 数组,用于按 SKU 存储商品
    • 一个方法 addProduct(Product $product): void,用于添加商品。如果已经存在 SKU 相同的商品,则抛出 LogicException 异常,错误消息为 "Product already exists: [sku]"
    • 一个方法 getProduct(string $sku): Product,用于按 SKU 返回商品。如果找不到商品,则抛出 InvalidArgumentException 异常,错误消息为 "Product not found: [sku]"
  • main.php:引入 Inventory 文件。你会收到 3 个输入:SKU、商品名称和一个操作("add"、"remove" 或 "duplicate")。

    创建一个 Inventory,并使用给定的 SKU、名称和初始数量 10 添加一个新的 Product。

    根据操作执行相应的步骤:

    • "add":对商品调用 addStock(5),然后打印 "Stock updated: [quantity]"
    • "remove":对商品调用 removeStock(15)(这应该会抛出异常)
    • "duplicate":尝试添加另一个 SKU 相同的商品(这应该会抛出异常)

    抛出异常时,打印异常的类名,后面接 ": " 和异常消息。使用 PHP 的 get_class() 函数获取类名。

这个挑战展示了不同类型的异常如何表示不同的问题,包括无效输入、运行时故障和逻辑错误,让你的代码能够更准确、更清晰地处理错误。

亲手试试

<?php

require_once 'Inventory.php';

// 读取输入
$sku = trim(fgets(STDIN));
$name = trim(fgets(STDIN));
$operation = trim(fgets(STDIN));

try {
    // TODO: 创建一个 Inventory 对象
    // TODO: 创建一个 Product 对象,使用给定的 SKU、名称和初始数量 10
    // TODO: 将商品添加到库存中
    
    // TODO: 根据操作执行以下步骤:
    // “add”:对商品调用 addStock(5),然后打印 "Stock updated: [quantity]"
    // “remove”:对商品调用 removeStock(15)
    // “duplicate”:尝试添加另一个具有相同 SKU 的商品
    
} catch (Exception $e) {
    // TODO: 打印异常类名,后面接 ": " 和异常消息
    // 提示:使用 get_class($e) 获取类名
}

?>
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: PHP 在线编译器