自定义异常的使用

<?php
// 报告所有错误(适用于开发环境)
ini_set('display_errors', 'On');
error_reporting(-1);

/**
 * 自定义异常(继承通用异常Exception)
 */
class MyException extends Exception
{
    /**
     * 构造方法
     *
     * @param string $message 异常信息
     * @param int $code 异常代码
     * @param Throwable|null $previous
     */
    public function __construct(string $message = '', int $code = 0, Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous); // 调用父类通用异常Exception的构造方法
    }
}

/**
 * Demo类
 */
class Demo
{
    /**
     * 测试方法(参数只允许传入bool数据类型,其余数据类型均抛出异常)
     *
     * @param mixed $var 任意参数(重要提醒:形参数据类型必须为mixed,不能为bool,否则会发生隐式转换导致永远不会抛出异常)
     * @return bool 若$var为bool数据类型则原样返回,否则抛出异常
     * @throws MyException 自定义异常
     */
    public function func(mixed $var): bool
    {
        if (is_bool($var)) {
            return $var;
        }

        ob_start();
        var_dump($var);
        $dump = trim(ob_get_clean());

        // 设置异常的message和code
        $message = "参数无效(仅支持bool类型),您输入的是:$dump";
        $code = 1024; // code可自定义

        throw new MyException($message, $code); // 抛出异常后不会再执行后面的代码

        // echo 'Unreachable statement'; // 这里不会执行,因为上面抛出了异常
    }
}

$demo = new Demo();

try {
    $demo->func(true);
    echo 'try-1   ===> 无异常' . PHP_EOL; // try-1   ===> 无异常
} catch (MyException $e) {
    echo 'catch-1 ===> ' . $e->getMessage() . PHP_EOL;
}

try {
    $demo->func(9527);
    echo 'try-2   ===> 无异常' . PHP_EOL;
} catch (MyException $e) {
    echo 'catch-2 ===> ' . $e->getMessage() . PHP_EOL; // catch-2 ===> 参数无效(仅支持bool类型),您输入的是:int(9527)
}

try {
    $demo->func(false);
    echo 'try-3   ===> 无异常' . PHP_EOL; // try-3   ===> 无异常
} catch (MyException $e) {
    echo 'catch-3 ===> ' . $e->getMessage() . PHP_EOL;
}


//========== 总结 ==========//
// 1、函数或方法如果可能会抛出异常,那么调用处必须使用try-catch捕获异常,因为如果不捕获异常而程序又恰好出现异常,那么系统就会报致命错
//    误“Fatal error: Uncaught MyException”。
// 2、PHP有很多标准异常和预定义异常,在创建自定义异常前可先查阅PHP官方文档,看是否有满足需求的标准异常或预定义异常,优先使用这些异常,
//    在不能满足需求的情况下才创建自定义异常。
//    其实PHP的标准异常和预定义异常已经覆盖了日常大部分错误,如数据类型错误可以使用TypeError,数据类型正确但值错误可以使用ValueError,
//    甚至除数为零时的错误DivisionByZeroError都为我们准备好了。
//    在大多数情况下,开发者都不需要创建自定义异常,只要使用new关键字创建标准异常或预定义异常的对象,并设置对象的$message属性为开发者
//    想展示的错误信息,然后通过throw关键字将异常对象抛出去即可。
//    PHP官方文档地址:https://www.php.net/manual/zh/spl.exceptions.php
// 3、Exception是通用异常,抛出该异常在维护和调试时帮助比较小,所以在实际开发中应该尽量使用标准异常、预定义异常、自定义异常。
// 4、写try-catch捕获异常时,try{}里面应该只写非稳定代码(即可能会抛出异常的代码),稳定代码不要写在try{}里面,最佳实践方案是每个try{}
//    里面有且只有一行会抛出异常的代码。
// 5、一段代码在执行过程中如果有多处地方可能会抛出异常,不要嵌套try{},也不要把所有非稳定代码都写在一个try{}里面,而是逐个单独处理,
//    这样在出现异常时能够更灵活地应对(如return或exit),代码也更容易维护。
// 6、try{}里面的函数或方法抛出异常后,函数或方法后面的代码就不会再执行了,而是转去执行异常对应的catch{},所以如果需要接收函数或方法
//    的返回值就要特别注意,如:$var = $demo->func(9527),由于func(9527)抛出了异常,后续代码都不会再执行了,所以$var变量并没有被定义,
//    后续使用$var会报Undefined variable的Warning,最安全的办法是在try{}前面先初始化$var变量。

// PHP标准库(SPL)提供的标准异常
// --------------------------------------------------
// class BadFunctionCallException extends LogicException
// class BadMethodCallException extends BadFunctionCallException
// class DomainException extends LogicException
// class InvalidArgumentException extends LogicException
// class LengthException extends LogicException
// class LogicException extends Exception
// class OutOfBoundsException extends RuntimeException
// class OutOfRangeException extends LogicException
// class OverflowException extends RuntimeException
// class RangeException extends RuntimeException
// class RuntimeException extends Exception
// class UnderflowException extends RuntimeException
// class UnexpectedValueException extends RuntimeException

// 预定义异常
// --------------------------------------------------
// class Exception implements Throwable
// class ErrorException extends Exception
// class Error implements Throwable
// class ArgumentCountError extends TypeError
// class ArithmeticError extends Error
// class AssertionError extends Error
// class DivisionByZeroError extends ArithmeticError
// class CompileError extends Error
// class ParseError extends CompileError
// class TypeError extends Error
// class ValueError extends Error
// class UnhandledMatchError extends Error
// final class FiberError extends Error

Copyright © 2024 码农人生. All Rights Reserved