Php的错误和异常及laravel的错误处理机制

php 的错误和异常

错误(error)指的是因为语法错误或者环境配置问题产生的报错,错误有16个错误等级, 有的错误等级会使脚本中断运行。 而异常(exception)指的是程序因为业务逻辑问题产生的意外情况。

在 php5 的时代, 错误不能被 try … catch … 捕获, 只能通过 error_reporting() 设置是否显示错误信息, 而遇到 E_ERROR 设置 error_reporting 也不管用, 因为 E_ERROR 报错脚本会直接终止运行。 异常是可以被捕获的, 不过同样比较悲催的是: php 解释器不会自动抛出异常。 它不能分辨你到底是业务逻辑问题还是语法问题, 几乎所有的业务逻辑问题最后都变成了两种情况: 一种是跑的通的bug(不容易察觉), 另一种是跑不通的错误(不能被捕获)。 除非你预先发现了你的业务逻辑问题, 然后手动抛出(throw), try…catch… 才能捕获到你抛出的异常。听起来好像多余, 因为如果事先预料到了问题, 直接改代码避免出问题不就好了? 但这并不是多此一举, 手动抛出异常然后捕获, 你就可以把你的异常处理代码和正常业务逻辑抽离出来, 在 try … catch 里面写正常代码, catch 里面写异常处理代码。

在 php7 事情有了转机, php7 中大多数错误可以作为 Error 异常(ErrorException)抛出了。 然后在 php8 时代所有的 Error 都能被捕获了。(不希望显示错误信息还是要设置 error_reporting 和 set_error_handler)

在 php8 时代所有的 Error 都能被捕获了 这句话是我说的,不是官网说的。具体情况还是自己测试一下比较好。

下面是 php 一些预置的错误和异常:

  • Throwable
    • Error
      • ArithmeticError
        • DivisionByZeroError
      • AssertionError
      • ParseError
      • TypeError
        • ArgumentCountError
      • CompileError
      • ValueError
      • UnhandledMatchError
      • FiberError
    • Exception
      • ClosedGeneratorException
      • DOMException
      • ErrorException
      • IntlException
      • LogicException
        • BadFunctionCallException
          • BadMethodCallException
        • DomainException
        • InvalidArgumentException
        • LengthException
        • OutOfRangeException
      • PharException
      • ReflectionException
      • RuntimeException
        • OutOfBoundsException
        • OverflowException
        • PDOException
        • RangeException
        • UnderflowException
        • UnexpectedValueException
      • SodiumException

可以通过下面的测试检查某个错误是否能被捕获。


<?php
set_error_handler("final_error_handle", E_ALL);
error_reporting(-1);
function final_error_handle($level,$message,$file,$line,$context){
    echo $level."\r\n";
}

function error_handle_custom($error){
    echo "是".get_class($error)."错误\r\n";
}

function exception_handle($exception){
    echo "是".get_class($exception)."异常\r\n";
}

function test($test, $testName){
    try{
            echo $testName.":\r\n";
            $test();
    }catch(Error $error){
            error_handle_custom($error);
            echo "错误已经处理了\r\n";
    }catch(Exception $exception){
            exception_handle($exception);
            echo "异常已经处理了\r\n";
    }
    echo "继续检查\r\n\r\n";
}
test(function(){
    $a = 5 / 0;
}, '除数为0');

// 除数为0:
// 捕获到了错误
// 是DivisionByZeroError错误
// 继续检查

test(function(){
    function a($a, $b){
        return $a+$b;
    }
    a(1);
}, '传递的参数太少');

// 传递的参数太少:
// 捕获到了错误
// 是ArgumentCountError错误
// 继续检查

test(function(){
    function b($a, $b){
        return $a+$b;
    }
    var_dump(b(1, 2, 3));
}, '传递的参数太多');

// 传递的参数太多:
// int(3)
// 继续检查

test(function(){
     function c(array $str){
        var_dump($str);
    }
    c(1);
}, '传入参数类型与参数类型申明不一致');

// 传入参数类型与参数类型申明不一致:
// 捕获到了错误
// 是TypeError错误
// 继续检查

test(function(){
    echo $what;
}, '调用未定义的变量');

// 调用未定义的变量:
// 捕获到了错误
// 是TypeError错误
// 继续检查

test(function(){
    u();
}, '调用未定义的函数');

// 调用未定义的函数:
// 捕获到了错误
// 是Error错误
// 继续检查

test(function(){
    $arr = json_decode('啊这这这');
    var_dump($arr);
}, 'json_decode 一个普通字符串');

// json_decode一个字符串:
// NULL
// 继续检查

test(function(){
 throw  new Exception('发生了一个错误');
}, '手动抛出异常');

// 手动抛出异常:
// 捕获到了异常
// 是Exception异常
// 继续检查

test(function(){
    file_get_contents('https://what.com');
}, '网络请求超时');

// 网络请求超时:
// 捕获到了错误
// 是TypeError错误
// 继续检查

Laravel 的错误处理机制

先看下 laravel 的 ExceptionHandle 是在哪里加载的。
Illuminate\Foundation\Http\Kernel 的 框架会载入 $bootstrappers 中的引导项。 第一项是 Event 第二项是 Config 第三个就是 Exception。

Php的错误与异常及laravel的错误

Illuminate\Foundation\Bootstrap\HandleExceptions 的 bootstrap 设置了 error_reporting set_error_handler set_exception_handlerregister_shutdown_function。我们知道设置了这几项之之后,所有的错误都可以被捕获并且不显示错误信息了。
Php的错误与异常及laravel的错误

首先看 handleError, 这里如果是 deprecation (弃用)错误的话,会直接处理, 如果不是的话会抛出 ErrorException
Php的错误与异常及laravel的错误

然后看 handleExceptionhandleExceptiongetExceptionHandler 然后执行 ExcptionHandler 的 reportrender 方法。
Php的错误与异常及laravel的错误

getExceptionHandler 到的就是 App\Exceptions\Handler::class

Php的错误与异常及laravel的错误

然后其他的知识直接看官方文档就好 renderablerender 直接给用户返回 response , report 是给程序员报告错误信息。

补充一下, App\Exceptions\Handler 继承了 Illuminate\Foundation\Exceptions\Handler , 然后里面有一些 Laravel 预置的异常。

protected $internalDontReport = [
        AuthenticationException::class,
        AuthorizationException::class,
        BackedEnumCaseNotFoundException::class,
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        MultipleRecordsFoundException::class,
        RecordsNotFoundException::class,
        SuspiciousOperationException::class,
        TokenMismatchException::class,
        ValidationException::class,
    ];

Php的错误和异常及laravel的错误处理机制

Php的错误和异常及laravel的错误处理机制

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!