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
收藏随意^^请保留教程地址.
评论已关闭