详聊PHP异常

异常和错误处理

在语言级别上,通常具有许多错误处理模式,但这些模式往往建立在约定俗成的基础上,也就是说这些错误是预知的,但是在大型程序中,如果每次调用都去逐一检查错误,会使代码变得冗余复杂,到处都是if...else,并且严重降低代码的可读性,而且人的因素也是不可信的,可能程序员并不会把这些问题当一回事,从而导致业务异常,在这种背景下,就逐渐形成了异常处理机制,或者强迫消除这些问题。

如何使用异常处理机制

异常的思想最早可以追朔到20世纪60年代,在c++,java中发扬光大,php则是借鉴两种语言的异常处理机制。 php里的异常,是程序运行中不符合预期的情况及正常流程不同的状况,一种不正常的情况,就是按照正常逻辑不该出错,但仍然出错的情况,这属于逻辑和业务流程的一种中断,而不是语法错误。php里的错误则属于自身问题,是一种非法语法或者环境问题导致的,让编译器无法通过检查甚至无法运行的情况. 在各种语言里,异常excepetion和错误error的概念是不一样的,在PHP里,遇到任何自身错误都会触发一个错误,而不是抛出异常(对于一些情况,会同时抛出错误和异常)。PHP一旦遇到非正常代码,通常都会触发错误,而不是抛出异常。在这个意义上,如果想使用异常处理不可预料的问题,是办不到的。比如,想在文件不存在或者数据库链接打开时触发异常,是不可行的。这在PHP里把它作为错误抛出,而不会作为异常自动捕获。 以经典除零问题为例

<?php
    $a = null;
    try {
        $a = 5/0;
        echo $a,PHP_EOL;
    } catch (Exception $e) {
        $e->getMessage();
        $a = -1;
    }
    echo $a;  //在这里php不会抛出异常,而是直接抛出错误

    ( ! ) Warning: Division by zero in D:\xampp\htdocs\php_study_test.php on line 6
    Call Stack
    #   Time    Memory  Function    Location
    1   0.0010  131904  {main}( )   ...\php_study_test.php:0
?>

由以上运行结果可以看到,对于除零这种“异常”情况,PHP会认为这是一个错误,直接触发错误,而不会自动自动抛出异常使程序进入异常流程,所以最终a的值不是预想中的-1.也就是说并没有进入异常分支,也没有处理异常。PHP只有你主动throw后,才能捕获异常(一般情况) 

再看Java代码

public class ExcepetionTry{
public static void tp() throws ArithmeticException{
    int a;
    a = 5/0;
    System.out.println("运算结果:" + a);
}

public static void main(String[] args){
    int a;
    try{
        a = 5/0;
        System.out.println("运算结果": + a);
    } catch (ArithmeticException e){
        e.printStackTrace();
    } finally{
            a = -1;
            System.out.println("运算结果": + a);
    }

    try{
            ExcepetionTry.tp();
    } catch (Exception e){
            System.out.println("异常被捕获");
        }
    }
}

//java.lang.ArithmeticException: / by zero
at dome.dome14.main(dome14.java:13)
运算结果:-1
异常被捕获

对于Java。则会认为除零属于ArithmeticException,会对其进行捕获,并对异常进行处理。也就是说PHP通常是无法自动捕获有意义的异常的。他把所有不正常的情况都视为错误,你要想捕获这个异常,就得使用if...else结构,保证代码是正常的,然后判断如果除数为0,则手动抛出异常,再捕获。Java有一套完整的异常机制,内置很多异常类会自动捕获各种异常,但PHP这个机制并不完善,PHP内建的常见异常类主要有pdoexception,reflectionexception。

也就是说PHP只有手动抛出异常后才能捕获异常,或者是有内建的异常机制时,会先触发错误,再捕获异常。那么PHP异常用法是什么样的呢?请看下面的例子

 先定义两个异常类

class emailException extends exception{

}

class pwdException extends exception{
    function __toString(){
        return "<div>Exception:{$this->getCode()} : {$this->getMessage()} in File:{$this->getFile()} on line:{$this->getLine()}</div>";
    }
}

function reg($reginfo = null){
    if(empty($reginfo) && !isset($reginfo)){
        throw new Exception("参数非法");
    }

    if(empty($reginfo['email'])){
        throw new emailException("邮箱为空");
    }

    if($reginfo['pwd'] != $reginfo['repwd']){
        throw new pwdException("两次输入的密码不一致");
    }

    echo '注册成功';
}

然后根据实际业务的需求抛出不同异常 

try {
    $regArr = ['email'=>'757256172@qq.com','pwd'=>'','repwd'=>002956];
    reg($regArr);
} catch (emailException $ee) {
    echo $ee->getMessage();
} catch (pwdException $pe){
    echo $pe;
    echo PHP_EOL,'特殊处理';
} catch (Exception $e){
    echo $e->getTraceAsString();
    echo PHP_EOL,'其他情况,统一处理';
}

这一段代码用于捕获所抛出的异常,进行分别处理

总结php异常到底该怎么用,在什么时候抛出异常,什么时候捕获异常,什么场景下能用异常。

对程序的悲观预测

如果一个程序员最自己的代码有悲观情绪,这里并不是指该程序员的代码质量不高,而是他认为自己的代码无法一一处理各种可预测,不可预测的情况,那该程序员就会进行异常处理,假设一个场景,程序员悲观的认为自己的这段代码在高并发的条件下可能产生死锁,那么他就会悲观的抛出异常,然后再死锁时进行捕获,对异常进行细致的处理。

程序的需要和对业务的关注

如果程序员希望业务代码中不会充斥大堆的打印,测试等处理,通常就会使用异常机制;或者自定义异常。如果程序员希望有预见性的处理可能发生的,会影响正常业务的代码,那么就需要异常,在这里,强调了异常是业务处理中必不可少的环节。异常机制认为,数据一直很重要,在数据一直性可能被破坏时,就需要异常机制进行事后补救。

举个例子。比如上传文件,需要把文件上传到指定目录中,然后返回文件的路径,并保存到数据库中去。保存到路径和保存到数据库中这两部就是互相关联的,密不可分的一个集成业务,缺一不可。如果文件保存失败,而插入数据库记录成功的话。就会导致文件无法下载。而文件保存成功,数据库没有保存成功,那么文件永远得不到下载。

那么假设文件保存成功后没有提示,但是保存失败会自动抛出异常,访问数据库也是一昂,插入成功没有提示,但是插入失败就会抛出异常,就可以把这两个有可能抛出异常的代码段包含在一个try语句里,然后用catch捕获错误,在catch代码段里删除没有记录到数据的文件或者删除没有文件的记录,以保证业务数据的一致性。因此,从业务角度来讲,异常偏重于保护业务数据一致性。并强调对异常业务的处理

<?php
    try{
        if(上传出错) throw(上传异常)
        if(插入数据库不成功) throw(数据库操作异常)
    } catch(异常)
        必须的补救错误,例如删除文件,删除数据库记录,
?>

语言级别的健壮性要求

异常就是无法控制的运行时错误,会到处出错时中断正常逻辑运行,该异常代码后面的逻辑都不能继续运行。那么try...catch处理的好处就是:可以把异常造成的逻辑中断破坏降到最小范围内,并且经过补救后不影响业务逻辑的完整性;乱抛出异常和只抛不捕获,或捕获而不补救,会导致数据混乱。这就是异常处理的一个重要作用,就是通过精确控制运行时的流程,在程序中断时,有预见的用try缩小可能出错的影响范围,及时捕获异常发生并作出相应补救,以使逻辑流程仍然能回到正常轨道上

 



上一篇: phpstorm配置xdebug上

下一篇: Linux配置SVN上篇

分享

版权属于:破冰者博客

文章链接:https://ice-breaker.cn/post/19

转载时必须以链接形式注明原始出处及本声明。

表情