PHP错误与异常处理

一、异常与错误的概述

 

PHP中什么是异常:

  程序在运行中出现不符合预期的情况,允许发生(你也不想让他出现不正常的情况)但他是一种不正常的情况,按照我们的正常逻辑本不该出的错误,但仍然会出现的错误,属于逻辑和业务流程的错误,而不是编译或者语法上的错误。

PHP中什么是错误:

属于php脚本自身的问题,大部分情况是由错误的语法,服务器环境导致,使得编译器无法通过检查,甚至无法运行的情况。warning、notice都是错误,只是他们的级别不同而已,并且错误是不能被try-catch捕获的。错误一般有三大分类:

①  语法错误

语法错误最常见,并且最容易修复。例如,遗漏了一个分号,就会显示错误信息。这类错误会阻止脚本执行。通常发生在程序开发时,可以通过错误报告进行修复,再重新运行。

②  运行时错误

这种错误一般不会阻止PHP脚本的运行,但是会阻止脚本做希望它所做的任何事情。例如,在调用header()函数前如果有字符输出,PHP通常会显示一条错误消息,虽然PHP脚本继续运行,但header()函数并没有执行成功。

③ 逻辑错误

这种错误实际上是最麻烦的,不但不会阻止PHP脚本的执行,也不会显示出错误消息。例如,在if语句中判断两个变量的值是否相等,如果错把比较运行符号“==”写成赋值运行符号“=”就是一种逻辑错误,很难会被发现。

 

PHP异常处理很鸡肋?
在上面的分析中我们可以看出,PHP并不能主动的抛出异常,但是你可以手动抛出异常,这就很无语了,如果你知道哪里会出问题,你添加if else解决不就行了吗,为啥还要手动抛出异常,既然能手动抛出就证明这个不是异常,而是意料之中。以我的理解,这就是PHP异常处理鸡肋的地方(不一定对啊)。所以PHP的异常机制不是那么的完美,但是使用过框架的同学都知道有这个情况:你在框架中直接写开头那段php“自动”捕获异常的代码是可以的,这是为什么?看过源码的同学都知道框架中都会涉及三个函数:register_shutdown_function,set_error_handler,set_exception_handler后面我会重点讲解着三个黑武器,通过这几个函数我们可以实现PHP假自动捕获异常和错误。

二、ERROR的级别

Fatal Error:致命错误(脚本终止运行)
E_ERROR // 致命的运行错误,错误无法恢复,暂停执行脚本
E_CORE_ERROR // PHP启动时初始化过程中的致命错误
E_COMPILE_ERROR // 编译时致命性错,就像由Zend脚本引擎生成了一个E_ERROR
E_USER_ERROR // 自定义错误消息。像用PHP函数trigger_error(错误类型设置为:E_USER_ERROR)

Parse Error:编译时解析错误,语法错误(脚本终止运行)
E_PARSE //编译时的语法解析错误

Warning Error:警告错误(仅给出提示信息,脚本不终止运行)
E_WARNING // 运行时警告 (非致命错误)。
E_CORE_WARNING // PHP初始化启动过程中发生的警告 (非致命错误) 。
E_COMPILE_WARNING // 编译警告
E_USER_WARNING // 用户产生的警告信息

Notice Error:通知错误(仅给出通知信息,脚本不终止运行)
E_NOTICE // 运行时通知。表示脚本遇到可能会表现为错误的情况.
E_USER_NOTICE // 用户产生的通知信息。

 

三、PHP异常处理中的黑武器(重点!!!)

set_error_handler — 设置用户自定义的错误处理函数

register_shutdown_function – 注册一个在关机时执行的函数

set_exception_handler – 设置用户定义的异常处理函数

<?php
/**
 * 创建可抛出一个异常的函数
 */
function checkNum($number) {
    if ($number > 1) {
        throw new Exception("Value must be 1 or below");
    }
    return true;
}
// 在 "try" 代码块中触发异常
try {
    checkNum(2);
    // 如果异常被抛出,那么下面一行代码将不会被输出

    echo 'If you see this, the number is 1 or below';
} catch (Exception $e) {
    //    "catch" 代码块接收到该异常,并创建一个包含异常信息的对象 ($e)。
    // 捕获异常
//    通过从这个 exception 对象调用 $e->getMessage(),输出来自该异常的错误消息。
    echo 'Message: ' . $e->getMessage();
}

捕获到一个错误:Message: Value must be 1 or below

 

set_exception_handler()函数可设置处理所有未捕获异常的用户定义函数。

<?php
/**
 * 设置一个顶级异常处理器
 */
function myexception($e) {
    echo 'this is top exception';
}
// 修改默认的异常处理器
set_exception_handler("myexception");
try {
    $i = 5;
    if ($i < 10) {//创建一个异常
        throw new Exception('$i must greater than 10');
    }
} catch (Exception $e) {
    // 处理异常
    echo $e->getMessage() . '<br/>';
    // 不处理异常,继续抛出
    throw new Exception('errorinfo'); // 也可以用throw $e 保留原错误信息;
}

创建一个自定义的异常类

<?php
class customException extends Exception {
    public function errorMessage() {
        $errorMsg = 'Error on line ' . $this->getLine() . ' in ' . $this->getFile() . ': <b>' . $this->getMessage() . '</b> is not a valid E-Mail address';
        return $errorMsg;
    }
}
// 使用
try {
    throw new customException('error message');
} catch (customException $e) {
    echo $e->errorMessage();
}

可以使用多个catch来返回不同情况下的错误信息

<?php
class customException extends Exception {
    public function errorMessage() {
        $errorMsg = 'Error on line ' . $this->getLine() . ' in ' . $this->getFile() . ': <b>' . $this->getMessage() . '</b> is not a valid E-Mail address';
        return $errorMsg;
    }
}
try {
    $i = 5;
    if ($i > 0) {
        throw new customException('error message'); // 使用自定义异常类处理
    }
    if ($i < -10) {
        throw new Exception('error2'); // 使用系统默认异常处理
    }
} catch (customException $e) {
    echo $e->getMessage();
} catch (Exception $e1) {
    echo $e1->getMessage();
}

發表回覆

你的電郵地址並不會被公開。 必要欄位標記為 *