首页 > PHP > PHP中异常类Exception的应用

PHP中异常类Exception的应用

各类变成语言的异常处理大致类似,只是php不像java强制要求开发者捕获异常,而是淡化了异常处理来降低开发复杂度,可以看出一般的CMS框架很少使用try{}catch(){}结构编程,虽然并不会影响程序执行,但是会给某些粗心的程序埋下地雷,出了问题不好排查。所以,在PHP开发过程中还是尽量捕获异常和抛出异常,这样可以让我们的代码更健壮。

PHP处理异常的流程大致如下:在异常抛出时,其后面的代码不会继续执行,PHP会尝试查找匹配catch代码块,如果异常没有捕获,而且又没有set_exception_handler()作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出"Uncaught Exception"(未捕获异常)。例如:

<?php
//我们先制造一个异常
function checkNum($number)
{
    if($number>1)
    {
        throw new Exception("Value must be 1 or below");
    }
    return true;
}

function test()
{
    //执行会抛出异常的代码
    checkNum(2);
}

//测试函数
test();
 
//执行会抛出异常的代码
checkNum(2);

执行这段程序就会抛出异常,异常内容是在第7行,抛出了"Value must be 1 or below"的异常,而在调用checkNum()函数的第15行附近并未找到try{}catch(){}代码块,并且又没有set_exception_handler()作相应的处理,就会导致程序中断。

如果我们使用set_exception_handler来捕获,添加以下代码:

function exception_handler ($exception)
{
    echo "Hi, this is an Exception";
}

set_exception_handler('exception_handler');

之后,即使是程序的任意位置抛出异常均会跳转到exception_handler()函数进行处理。

其实,这样的功能和java的try{}catch(){}finally{}的处理倒是很像,不过又有很大的区别。java是之前不管你有没有捕获异常都会执行finally{}中的代码,而php发现了try{}catch(){}代码块处理了异常,并不会去调用set_exception_handler()定义的函数。例如:

<?php
//我们先制造一个异常
function checkNum($number)
{
    if($number>1)
    {
        throw new Exception("Value must be 1 or below");
    }
    return true;
}

function test()
{
    try{
        //执行会抛出异常的代码
        checkNum(2);
    }catch(Exception $e){
        
    }
}

function exception_handler ($exception)
{
    echo "Hi, this is an Exception";
}

set_exception_handler('exception_handler');

//测试函数
test();

运行之后,并不会有任何输出,说明exception_handler()并未执行。

话说,在test()函数中捕获了异常之后,如果当前并不需要处理异常咋办?test()可以继续抛出异常给上一层,即调用test()函数的第30行。

那么,修改代码如下:

<?php
//我们先制造一个异常
function checkNum($number)
{
    if($number>1)
    {
        throw new Exception("Value must be 1 or below");
    }
    return true;
}

function test()
{
    try{
        //执行会抛出异常的代码
        checkNum(2);
    }catch(Exception $e){
            //将异常信息和异常代码抛出
        throw new Exception($e->getMessage(), $e->getCode());
    }
}

try{
    //测试函数
    test();
}catch(Exception $e){
    echo "Hi, this is an Exception";
}

这样的处理在嵌套模块处理时非常有用,可以将各个地方的异常抛出到逻辑代码部分统一处理。

除了PHP自身的Exception之外,很多开源代码都会继承该类并实现自身的异常类。下面是官方手册给出的Exception的结构。

<?php
class Exception
{
    protected $message = 'Unknown exception';   // 异常信息
    private   $string;                          // __toString cache
    protected $code = 0;                        // 用户自定义异常代码
    protected $file;                            // 发生异常的文件名
    protected $line;                            // 发生异常的代码行号
    private   $trace;                           // backtrace
    private   $previous;                        // previous exception if nested exception

    public function __construct($message = null, $code = 0, Exception $previous = null);

    final private function __clone();           // Inhibits cloning of exceptions.

    final public  function getMessage();        // 返回异常信息
    final public  function getCode();           // 返回异常代码
    final public  function getFile();           // 返回发生异常的文件名
    final public  function getLine();           // 返回发生异常的代码行号
    final public  function getTrace();          // backtrace() 数组
    final public  function getPrevious();       // 之前的 exception
    final public  function getTraceAsString();  // 已格成化成字符串的 getTrace() 信息

    // Overrideable
    public function __toString();               // 可输出的字符串
}
?>

实现自定义异常类

<?php
header('Content-type:text/html;charset=utf-8');
/**
 * 自定义一个异常处理类
 */
class MyException extends Exception
{
    // 重定义构造器使 message 变为必须被指定的属性
    public function __construct($message, $code = 0, Exception $previous = null) {
        // 自定义的代码
 
        // 确保所有变量都被正确赋值
        parent::__construct($message, $code, $previous);
    }
 
    // 自定义字符串输出的样式
    public function __toString() {
        return __CLASS__ . ": [{$this->code}]: {$this->message}<br/>";
    }
 
    public function customFunction() {
        echo "A custom function for this type of exception<br/>";
    }
    
}
 
/**
 * 创建一个用于测试异常处理机制的类
 */
class TestException
{
    public $var;
 
    const THROW_NONE    = 0;
    const THROW_CUSTOM  = 1;
    const THROW_DEFAULT = 2;
 
    function __construct($avalue = self::THROW_NONE) {
 
        switch ($avalue) {
            case self::THROW_CUSTOM:
                // 抛出自定义异常
                throw new MyException('1 is an invalid parameter', 5);
                break;
 
            case self::THROW_DEFAULT:
                // 抛出默认的异常
                throw new Exception('2 is not allowed as a parameter', 6);
                break;
 
            default: 
                // 没有异常的情况下,创建一个对象
                $this->var = $avalue;
                break;
        }
    }
}

// 例子 1, 如果抛出的是一个自定义的异常,那么将会被MyException $e catch住
try {
    $o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) {      // 捕获异常
    echo "demo1:捕获到我的异常<br/>", $e;
    $e->customFunction();
} catch (Exception $e) {        // 被忽略
    echo "demo1:捕获到普通异常<br/>", $e;
}

// 例子 2, 如果抛出的是一个普通的异常,那么将会被Exception $e catch住
try {
    $o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) {      //  不能匹配异常的种类,被忽略
    echo "demo2:捕获到我的异常br/>", $e;
    $e->customFunction();
} catch (Exception $e) {        // 捕获异常
    echo "demo2:捕获到普通异常<br/>", $e;
}

// 例子 3, 如果抛出的是一个自定义的异常,同时不存在MyException $e的catch, 那么将会被Exception $e catch住
try {
    $o = new TestException(TestException::THROW_CUSTOM);
}catch (Exception $e) {        // 被忽略
    echo "demo3:捕获到普通异常<br/>", $e;
}

// 例子 4, 如果抛出的是一个普通异常,同时不存在Exception $e的catch, 此异常也不会被MyException $e catch住,只会抛出一个Fatal error:  Uncaught exception 'Exception'(未捕获的异常)
try {
    $o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) {      // 捕获异常
    echo "demo4:捕获到我的异常<br/>", $e;
    $e->customFunction();
}

// Continue execution
var_dump($o); // Null
echo "<br/>";

使用异常处理虽然会增加编码的复杂度,但是对于程序的调试追踪非常有用,而且可以写出强壮的代码。

本文链接:http://blog.zhengshuiguang.com/php/exception.html

收藏随意^^请保留教程地址.

标签:exception 异常 错误 捕获

评论已关闭