PHP的错误和异常处理总结
PHP内置了一批与错误和异常处理相关的 函数 ,本文会对其中部分函数进行详细说明。
set_error_handler
和 restore_error_handler
set_error_handler
可以设定当程序出现错误时,将对应的错误交给用户自定义的逻辑来处理。 leo108's blog
但是并不是所有的错误都可以被 set_error_handler
所指定的处理逻辑捕获,例如: E_ERROR
、 E_PARSE
、 E_CORE_ERROR
、 E_CORE_WARNING
、 E_COMPILE_ERROR
、 E_COMPILE_WARNING
,简单来说就是原本就会导致程序终止的错误都无法被捕获。 PHP的错误和异常处理总结
set_error_handler
只能设置一个错误处理逻辑,多次调用 set_error_handler
只有最后一次的那生效:
set_error_handler(function($errno, $errstr){
echo 'catch error1';
});
set_error_handler(function($errno, $errstr){
echo 'catch error2';
});
trigger_error('something error');
输出的是 leo108's blog
catch error2
在编写一个第三方代码库的时候,如果希望能够捕获代码库中的错误,又不影响调用方对错误的处理,可以使用 restore_error_handler
函数: PHP
function third_party_function() {
//第三方类库的错误处理逻辑
set_error_handler(function() {
//一些代码
});
//该第三方类库的逻辑
//一些代码
//复原错误处理逻辑
restore_error_handler();
}
这样,第三方代码库中出现的错误就会被第三方代码库的错误处理逻辑捕获,而在这个第三方代码库之外的错误还是由原本的逻辑处理。
如果错误处理逻辑的返回值是 false
,则PHP会调用内置的错误处理逻辑(例如根据 error_reporting
的值判断是否打印错误信息,写错误日志等);而返回 true
则不会调用内置处理逻辑,在执行完自定义的错误处理逻辑之后,会返回触发错误的地方继续往下执行。
error_reporting
以及 @
符号不会影响错误处理逻辑的调用:
error_eporting(0);
set_error_handler(function($errno, $errstr){
echo 'catch error';
});
@trigger_error('something error');
上述代码会输出:
catch error
对于无法被 set_error_handler
捕获的错误常见的只有 E_ERROR
和 E_PARSE
两个。前者可能是内存使用超过设定的值、实例化一个不存在的类或者是调用一个不存在的函数;后者通常是语法解析错误例如漏写一个分号。对于 E_PARSE
,由于是语法层面的错误,所以没有办法去捕获处理。但对于 E_ERROR
则可以通过 register_shutdown_function
以及 error_get_last
两个函数来处理,示例代码如下:
error_reporting(0);
register_shutdown_function(function() {
$error = error_get_last();
if ($error != null && $error['type'] == E_ERROR) {
echo "fatal error catched:" . var_export($error, true);
}
});
new test();
输出:
fatal error catched:array (
‘type’ => 1, PHP的错误和异常处理总结
‘message’ => ‘Class ‘test’ not found’, PHP的错误和异常处理总结
‘file’ => ‘/tmp/error.php’,
‘line’ => 20,
)
set_exception_handler
和 restore_exception_handler
这两个函数和 set_error_handler
的两个函数差不多,同样是只能注册一个异常处理逻辑,多次注册只有最后一个生效;可以通过 restore_exception_handler
来恢复之前的异常处理逻辑。 leo108's blog
一些小实验
在错误处理逻辑中触发错误
set_error_handler(function($errno, $errstr){
echo 'catch error:' . $errstr . PHP_EOL;
trigger_error('error in error handler');
});
trigger_error('origin error');
输出: leo108's blog
catch error:origin error
PHP Notice: error in error handler in /tmp/error.php on line 15
结论:在错误处理逻辑中的错误是无法被再次捕获。 异常
在异常处理逻辑中抛出异常
set_exception_handler(function(Exception $e){
echo 'catch exception:' . $e->getMessage() . PHP_EOL;
throw new Exception('exception in exception handler');
});
throw new Exception('origin exception');
输出: 推酷是个无耻的网站
catch exception:origin exception
PHP Fatal error: Uncaught exception ‘Exception’ with message ‘exception in exception handler’ in /tmp/error.php:15 http://leo108.com/pid-2216.asp
Stack trace: 异常
0 [internal function]: {closure}(Object(Exception))
1 [main]
thrown in /tmp/error.php on line 15 http://leo108.com
结论:在异常处理逻辑中抛出的异常不会被捕获 http://leo108.com/pid-2216.asp
同时定义了异常和错误处理逻辑,在错误处理逻辑中抛出异常,在异常处理逻辑中触发错误
set_exception_handler(function(Exception $e){
echo 'catch exception:' . $e->getMessage() . PHP_EOL;
trigger_error('error in exception handler');
});
set_error_handler(function($errno, $errstr){
echo 'catch error:' . $errstr . PHP_EOL;
throw new Exception('exception in error handler');
});
外部触发了错误
trigger_error('origin error');
输出:
catch error:origin error
catch exception:exception in error handler
catch error:error in exception handler
PHP Fatal error: Uncaught exception ‘Exception’ with message ‘exception in error handler’ in /tmp/error.php:9
Stack trace:
0 [internal function]: {closure}(1024, ‘error in except…’, ‘/tmp/error.php’, 5, Array)
1 /tmp/error.php(5): trigger error(‘error in except…’)
2 [internal function]: {closure}(Object(Exception))
3 [main]
thrown in /tmp/error.php on line 9
结论:调用了两次错误处理逻辑,一次异常处理逻辑。
外部抛出异常
throw new Exception('origin exception');
输出: