/*
* 1 interface Throwable
2 |- Exception implements Throwable
3 |- ...
4 |- Error implements Throwable
5 |- TypeError extends Error
6 |- ParseError extends Error
7 |- ArithmeticError extends Error
8 |- DivisionByZeroError extends ArithmeticError
9 |- AssertionError extends Error
* */
先列一下php有哪些关于错误异常警告相关设置和处理
1. 内部函数:error_reporting
2. ini配置:display_errors
3. ini配置: log_errors和error_log
4. set_exception_handler
5. set_error_handler
6. try/catch
1. error_reporting和display_errors,log_errors和error_log是针对于PHP标准错误处理机制(输出stderr,和error_log)所设置的,对set_exception_handler和set_error_handler没有机制没有影响
2. set_exception_handler 处理执行期间 用户期间 ERROR和EXCEPTION
3. set_error_handler 处理执行期间 内部期间 ERROR和EXCEPTION,WARNING,Undefined
直接讲各个场景的例子
在PHP7,ERROR级别跟EXCEPTION异常是一样的错误,所以这2个类型只讲一个
1. ERROR级别,有try catch捕获, 有set_exception_handler
error_reporting(E_ALL ^ E_NOTICE);
function exceptHandle($ex) {
echo 'errorHandle' . $ex->getMessage().'\n';
}
set_exception_handler('exceptHandle');
try {
$a = sdfsdf(); //没有定义的函数
} catch (Exception $e) { // 捕获用户自定义异常
var_dump("Exception");
var_dump($e);
} catch (Error $e) { // 捕获Error, TypeError, ArithmeticError, DivisionByZeroError, AssertionError
var_dump("Error");
var_dump($e);
}
结论: 这个错误会被try cache捕获,不会进入到set_exception_handler处理,也不会被PHP标准错误处理
2. ERROR级别, 没有try catch捕获,有set_exception_handler
error_reporting(E_ALL ^ E_NOTICE);
function exceptHandle($ex) {
echo 'errorHandle' . $ex->getMessage().'\n';
}
set_exception_handler('exceptHandle');
$a = sdfsdf(); //没有定义的函数
结论: 这个错误最后被set_exception_handler处理, 不会被PHP标准错误处理
3. ERROR级别, 没有try catch捕获,没有set_exception_handler
error_reporting(E_ALL ^ E_NOTICE);
$a = sdfsdf(); //没有定义的函数
结论: 由于这个ERROR级别错误,而且error_reporting只过滤NOTICE级别的错误,这个错误最后被PHP标准错误处理(stderr,error_log)
4. NOTICE级别, 有set_error_handler,返回true
error_reporting(E_ALL ^ E_NOTICE);
function errorHandle($errno, $errstr, $errfile, $errline) {
echo 'errorHandle' . date('Y-m-d H:i:s') . $errno . $errstr . $errfile . $errline.'\n';
return true; // true 不传递给PHP标准错误处理
}
set_error_handler('errorHandle');
$a = [];
echo $a['asdf'].'\n'; // 访问没有index的数组下标
结论: 由于这个NOTICE级别错误,try catch不能捕获这个级别类的错误所以不用,这个错误最后被set_error_handler,
set_error_handler返回true, 所以不传递给PHP标准错误处理
5. NOTICE级别, 有set_error_handler,返回false
error_reporting(E_ALL ^ E_NOTICE);
function errorHandle($errno, $errstr, $errfile, $errline) {
echo 'errorHandle' . date('Y-m-d H:i:s') . $errno . $errstr . $errfile . $errline.'\n';
return false; // false 传递给PHP标准错误处理
}
set_error_handler('errorHandle');
$a = [];
echo $a['asdf'].'\n'; // 访问没有index的数组下标
结论: 由于这个NOTICE级别错误,try catch不能捕获这个级别类的错误所以不用,这个错误最后被set_error_handler,
set_error_handler返回false, 同时传递给PHP标准错误处理处理,但是由于error_reporting过滤掉NOTICE,所以PHP标准错误处理直接返回不处理
6. NOTICE级别, 没有set_error_handler
error_reporting(E_ALL ^ E_NOTICE);
$a = [];
echo $a['asdf'].'\n'; // 访问没有index的数组下标
结论: 由于这个NOTICE级别错误,try catch不能捕获这个级别类的错误所以不用,最后被PHP标准错误处理处理,
但是由于error_reporting过滤掉NOTICE,所以PHP标准错误处理直接返回不处理
7. Warning级别, 有set_error_handler,返回true
error_reporting(E_ALL ^ E_NOTICE);
function errorHandle($errno, $errstr, $errfile, $errline) {
echo 'errorHandle' . date('Y-m-d H:i:s') . $errno . $errstr . $errfile . $errline.'\n';
return true; // true 不传递给PHP标准错误处理
}
set_error_handler('errorHandle');
$B = SDFSDF; // Warning 访问没有定义的常量
结论: 由于这个Warning级别错误,try catch不能捕获这个级别类的错误所以不用,这个错误最后被set_error_handler,
set_error_handler返回true, 所以不传递给PHP标准错误处理
8. Warning级别, 有set_error_handler,返回false
error_reporting(E_ALL ^ E_NOTICE);
function errorHandle($errno, $errstr, $errfile, $errline) {
echo 'errorHandle' . date('Y-m-d H:i:s') . $errno . $errstr . $errfile . $errline.'\n';
return false; // false 传递给PHP标准错误处理
}
set_error_handler('errorHandle');
$B = SDFSDF; // Warning 访问没有定义的常量
结论: 由于这个Warning级别错误,try catch不能捕获这个级别类的错误所以不用,这个错误最后被set_error_handler,
set_error_handler返回false, 同时传递给PHP标准错误处理处理,由于error_reporting过滤掉NOTICE,所以PHP标准错误处理会处理改错误
9. Warning级别, 没有set_error_handler
error_reporting(E_ALL ^ E_NOTICE);
$B = SDFSDF; // Warning 访问没有定义的常量
结论: 由于这个Warning级别错误,try catch不能捕获这个级别类的错误所以不用,最后被PHP标准错误处理处理,
由于error_reporting过滤掉NOTICE,所以PHP标准错误处理会处理改错误
//下面都是这篇文章的历史版本, 最终已上面为准
/*
* 1.error_reporting(E_ALL ^ E_NOTICE)
* 比如 error_reporting(E_ALL ^ E_NOTICE), 针对于E_NOTICE(未定义的变量或者没有对应下标的索引)错误,假如触发了这个错误
* 如果用户自定义了set_error_handler,则被如果用户自定义了set_error_handler处理
* 如果没有set_error_handler,那么就会交给PHP标准错误处理, 但是由于error_reporting(E_ALL ^ E_NOTICE) 排除了E_NOTICE的错误,
* 所以php标准错误处理没有处理
*
* 2.error_reporting(E_ALL)
* 比如 error_reporting(E_ALL), 针对于E_NOTICE(未定义的变量或者没有对应下标的索引)错误,假如触发了这个错误
* 如果用户自定义了set_error_handler,则被如果用户自定义了set_error_handler处理
* 如果没有set_error_handler,或者定义了set_error_handler但是错误函数返回了false的话,这2种情况会把 E_NOTICE 传递给PHP标准错误处理
* 那么就会交给PHP标准错误处理, 由于error_reporting(E_ALL) 包含了E_NOTICE的等级错误,
* 所以php标准错误处理会处理这个错误,根据display_errors = on 显示到标准输出上,
* log_errors = on && error_log = path都定义的话,也会把这个E_NOTICE错误记录到对应的日志文件
*
* 3.总结
* error_reporting 只是针对报告给php标准错误处理的错误等级设置
* 而用户自定义处理try/catch和set_error_handler/set_exception_handler,可以捕获能捕获到的ERROR和Exception,跟error_reporting设置无关
* error_reporting的设置只是用于处理已经越过用户自定义错误处理的那些错误(传递给php标准错误处理这里)才有效
*
* set_error_handler 如果捕获到错误,返回true 就不传递给php标准错误处理, 如果返回false的话 传递给php标准错误处理
* set_exception_handler 捕获到的错误和异常, 不管返回true还是false,都不传递给php标准错误处理
*
* 手动try/catch优先级更高,没有手动捕获的,才会经过上面流程处理
*
*/
// 如果用户没有手动try/cache ($Error || $Throwable) 捕获Error(为定义函数之类), TypeError(函数参数类型错误), ArithmeticError, DivisionByZeroError, AssertionError的话 (运行时的错误),如果有注册set_exception_handler的话,就会被执行,否者如果有手动try/cache的话,就不会执行 set_exception_handler
// set_exception_handler 只是会类似钩子记录下日志,不会影响运行脚本的周期
// 这类错误要手动try/cache捕获, 不然会终止脚本运行,
// 如果用户没有手动try/cache ($Exception || $Throwable) 捕获Exception(throw new Exception("sdf"))的话 (用户抛出的逻辑异常的时候),如果有注册set_exception_handler的话,就会被执行,否则如果有手动try/cache的话,就不会执行 set_exception_handler
// set_exception_handler 只是会类似钩子记录下日志,不会影响运行脚本的周期
// 这类Exception错误要手动try/cache捕获, 不然会终止脚本运行,
set_exception_handler('exceptHandle');
// ParseError(编译语法解析时的错误) 语法错误是一种特殊的,在php脚本编译期间发生的错误,由于我们自定义错误和手动捕获, 都还没有执行,所以不走用户自定义错误处理,最后走php.ini的错误处理记录
function exceptHandle($ex) {
var_dump("exceptHandle");
var_dump(date('Y-m-d H:i:s') . $ex->getMessage() . PHP_EOL . $ex->getTraceAsString() . "\r\n");
}
// 捕获一些, Undefined index:, Undefined variable 的错误,这类错误不会被trycatch到,但可以被set_error_handler处理,不处理也不会终止脚本
set_error_handler('errorHandle');
// 总结: Undefined index:, Undefined variable 这类语法的错误,不会被trycatch到,但可以被set_error_handler处理,不处理也不会终止脚本
// 其他类型的错误,如果有try/catch优先被这个处理,否则如果有set_exception_handler则被这个处理, 再次之就是被默认php.ini处理
// 错误和异常如果不手动try/catch的话会被终止脚本
// ParseError 这类语法的错误,脚本都没编译好,更不可能执行,所以用户都处理不了,只有php内核处理
function errorHandle($errno, $errstr, $errfile, $errline) {
var_dump("errorHandle");
var_dump($errstr);
}
function sdfsdsdgsdf(array $sa)
{
}
try {
$a = $b;
} catch (Exception $e) { // 捕获用户自定义异常
var_dump("Exception");
var_dump($e);
} catch (Error $e) { // 捕获Error, TypeError, ArithmeticError, DivisionByZeroError, AssertionError
var_dump("Error");
var_dump($e);
}
exit();