各类变成语言的异常处理大致类似,只是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}
";
}
public function customFunction() {
echo "A custom function for this type of exception
";
}
}
/**
* 创建一个用于测试异常处理机制的类
*/
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:捕获到我的异常
", $e;
$e->customFunction();
} catch (Exception $e) { // 被忽略
echo "demo1:捕获到普通异常
", $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:捕获到普通异常
", $e;
}
// 例子 3, 如果抛出的是一个自定义的异常,同时不存在MyException $e的catch, 那么将会被Exception $e catch住
try {
$o = new TestException(TestException::THROW_CUSTOM);
}catch (Exception $e) { // 被忽略
echo "demo3:捕获到普通异常
", $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:捕获到我的异常
", $e;
$e->customFunction();
}
// Continue execution
var_dump($o); // Null
echo "
";
使用异常处理虽然会增加编码的复杂度,但是对于程序的调试追踪非常有用,而且可以写出强壮的代码。
收藏随意^^请保留教程地址.