PHP 中 Error 与 Exception 的区别,及如何捕获

文章目录

    写了一段 JSON 解析的代码,由于数据源不能保证一定是 JSON,所以解析可能失败。
    但是 PHP 的 json_decode 遇到无法解析的字符串,是不报错的,会直接返回空。而即使能解析出来,我也不太敢相信里面的字段是始终一致的。所以,不但需要判断能否解析成 JSON,还要判断字段是否缺少。出于偷懒的考虑,我想只捕获异常就好了,例如要捕获

    Trying to get property of non-object

    但是,下面的 try catch 怎么也捕获不到异常

    try {
        // Code that may throw an Exception or Error.
    } catch (\Exception $t) {
        // Handle exception
    }
    

    Google 了一下,才知道,PHP 中除了 Exception 还有 Error 的概念,而 Trying to get property of non-object,很不幸就属于 Error。

    PHP 中 error 与 exception 的区别

    看了几篇关于 PHP error 和 exception 区别的介绍文章,感觉都没有说到点上。我突然想,我为啥一定要知道他们的区别,因为我觉得这个设计是有问题的。例如,PHP5 时代,try catch 只能捕获 Exception,而不能捕获 Error。我非常不能理解 PHP 5 这种设计的意义是什么?而 PHP7 的处理方式,说明了我的观点是正确的。所以,我就没有兴趣去深究其起初的设计思路了。

    PHP 7 的新特性

    From now on, most of the errors are reported through the exception class Error.

    即,PHP 7 开始,Error 与 Exception 都是继承自 Throwable。

    从 Throwable 的继承关系,可以看到 Error 与 Exception 是平级的关系。

    interface Throwable
      |- Error implements Throwable
          |- ArithmeticError extends Error
              |- DivisionByZeroError extends ArithmeticError
          |- AssertionError extends Error
          |- ParseError extends Error
          |- TypeError extends Error
              |- ArgumentCountError extends TypeError
      |- Exception implements Throwable
          |- ClosedGeneratorException extends Exception
          |- DOMException extends Exception
          |- ErrorException extends Exception
          |- IntlException extends Exception
          |- LogicException extends Exception
              |- BadFunctionCallException extends LogicException
                  |- BadMethodCallException extends BadFunctionCallException
              |- DomainException extends LogicException
              |- InvalidArgumentException extends LogicException
              |- LengthException extends LogicException
              |- OutOfRangeException extends LogicException
          |- PharException extends Exception
          |- ReflectionException extends Exception
          |- RuntimeException extends Exception
              |- OutOfBoundsException extends RuntimeException
              |- OverflowException extends RuntimeException
              |- PDOException extends RuntimeException
              |- RangeException extends RuntimeException
              |- UnderflowException extends RuntimeException
              |- UnexpectedValueException extends RuntimeException
    

    捕获 Trying to get property of non-object 的方法

    try {
        // Code that may throw an Exception or Error.
    } catch (\Throwable $t) {
        // Handle exception
    }
    

    同时兼容 PHP 5 和 PHP 7 的写法

    try {
        // Code that may throw an Exception or Error.
    } catch (\Throwable $t) {
        // Executed only in PHP 7, will not match in PHP 5.x
    } catch (\Exception $e) {
        // Executed only in PHP 5.x, will not be reached in PHP 7
    }
    

    一些内置方法

    interface Throwable
    {
        public function getMessage(): string;       // Error reason
        public function getCode(): int;             // Error code
        public function getFile(): string;          // Error begin file
        public function getLine(): int;             // Error begin line
        public function getTrace(): array;          // Return stack trace as array like debug_backtrace()
        public function getTraceAsString(): string; // Return stack trace as string
        public function getPrevious(): Throwable;   // Return previous `Trowable`
        public function __toString(): string;       // Convert into string
    }
    

    记录异常的具体信息

    例如

    • 出错的代码文件,行数
    • 具体的错误信息
    • 错误类型

    使用更精确的捕获,还是更宽泛的捕获

    还是得分情况

    例如,MySQL 的唯一索引异常,我就习惯精确捕获。因为,需要特殊处理。

    而,其他大部分情况,我觉得直接宽泛的捕获 Throwable 即可。
    原因是,通常使用 try catch 是为了忽略异常,例如一些小概率的不影响逻辑的异常。
    本身也没有处理的必要,所以具体是什么异常,并不是太重要,只要记录好日志就可以了。

    奇怪的问题

    在非 Laravel 的普通 PHP 脚本中,我却捕获不到 Trying to get property of non-object 的异常。
    即使设置了

    error_reporting(-1);
    

    也不行。

    其会报一个提示信息,然后继续向下执行。。。PHP 太爷们了。。。

    PHP Notice: Trying to get property of non-object in /tmp/example.php on line 13

    找了半天没找到解决办法。算了,除了 Laravel 和 wordpress 我目前也没有用 PHP 的场景。

    参考

    • https://trowski.com/2015/06/24/throwable-exceptions-and-errors-in-php7/
    • https://blog.eleven-labs.com/en/fr/php7-throwable-error-exception/
    • http://php.net/manual/zh/language.errors.php7.php

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式