/ PHP

PHP的错误和异常处理总结

PHP的错误和异常处理总结

PHP内置了一批与错误和异常处理相关的函数,本文会对其中部分函数进行详细说明。

set_error_handlerrestore_error_handler

set_error_handler可以设定当程序出现错误时,将对应的错误交给用户自定义的逻辑来处理。

但是并不是所有的错误都可以被set_error_handler所指定的处理逻辑捕获,例如:E_ERRORE_PARSEE_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_COMPILE_WARNING,简单来说就是原本就会导致程序终止的错误都无法被捕获。

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');

输出的是

catch error2

在编写一个第三方代码库的时候,如果希望能够捕获代码库中的错误,又不影响调用方对错误的处理,可以使用restore_error_handler函数:

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_ERRORE_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,

‘message’ => ‘Class ‘test’ not found’,

‘file’ => ‘/tmp/error.php’,

‘line’ => 20,

)

set_exception_handlerrestore_exception_handler

这两个函数和set_error_handler的两个函数差不多,同样是只能注册一个异常处理逻辑,多次注册只有最后一个生效;可以通过restore_exception_handler来恢复之前的异常处理逻辑。

一些小实验

在错误处理逻辑中触发错误

set_error_handler(function($errno, $errstr){
    echo 'catch error:' . $errstr . PHP_EOL;
    trigger_error('error in error handler');
});
trigger_error('origin error');

输出:

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

Stack trace:

0 [internal function]: {closure}(Object(Exception))

1 [main]

thrown in /tmp/error.php on line 15

结论:在异常处理逻辑中抛出的异常不会被捕获

同时定义了异常和错误处理逻辑,在错误处理逻辑中抛出异常,在异常处理逻辑中触发错误

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): triggererror(‘error in except…’)

2 [internal function]: {closure}(Object(Exception))

3 [main]

thrown in /tmp/error.php on line 9

结论:调用了两次错误处理逻辑,一次异常处理逻辑。

外部抛出异常

throw new Exception('origin exception');

输出:

catch exception:origin exception

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): triggererror(‘error in except…’)

2 [internal function]: {closure}(Object(Exception))

3 [main]

thrown in /tmp/error.php on line 9

结论:异常处理逻辑和错误处理逻辑各被调用一次。

PHP的错误和异常处理总结
Share this