1、PHP的异常和错误php
异常:在程序运行中不符合预期的状况及与正常流程不一样的状况。一种不正常的状况,就是按照正常逻辑不应出错,但任然出错的状况,这属于逻辑和业务流程的一种中断,而不是语法错误。PHP只有主动 throw 后,才能捕获异常(通常状况下是这样,也有一些异常PHP能够自动捕获)html
错误:属于自身问题,是一种非法语法或环境问题致使,让编译器没法经过检查甚至没法运行的状况。(简单说就是使脚本运行不正常的状况)程序员
2、错误的级别thinkphp
大体分为几类:数据库
一、deprecated,最低级别的错误,表示“不推荐、不建议”。通常是因为使用不推荐的、过期的函数或语法形成的。虽不会影响PHP正常流程,但通常状况下建议修正。vim
二、notice,通常告诉你语法中存在不当的地方。如使用的变量未定义、数组索引是字符时没有加引号,php视为常量去查找,找不到再视为变量。数组
不影响PHP正常流程。服务器
三、warning,比较高的错误,在语法中出现很不恰当的状况下才报此错误,好比函数参数不匹配。这种级别的会致使得不到预期结果,故须要修改代码。php7
四、fetal error,致命错误,直接致使PHP流程终结,后面的代码再也不执行。好比调用一个不存在的方法,此错误必须处理。app
五、prase error,最高级别的错误,语法解析错误。属于语法检查阶段错误,致使PHP没法经过语法检查。
PHP手册中一共定义了16个级别的错误,最多见的就这几个。
level 可能的值:
1 E_ERROR 致命的运行错误。错误没法恢复,暂停执行脚本。 2 E_WARNING 运行时警告(非致命性错误)。非致命的运行错误,脚本执行不会中止。 4 E_PARSE 编译时解析错误。解析错误只由分析器产生。 8 E_NOTICE 运行时提醒(这些常常是你代码中的bug引发的,也多是有意的行为形成的。)
16 E_CORE_ERROR PHP 启动时初始化过程当中的致命错误。 32 E_CORE_WARNING PHP启动时初始化过程当中的警告(非致命性错)。
64 E_COMPILE_ERROR 编译时致命性错。这就像由Zend脚本引擎生成了一个E_ERROR。 128 E_COMPILE_WARNING 编译时警告(非致性错)。这就像由Zend脚本引擎生成了E_WARNING警告。
256 E_USER_ERROR 自定义错误消息。像用PHP函数trigger_error(程序员设置E_ERROR) 512 E_USER_WARNING 自定义警告消息。像用PHP函数trigger_error(程序员设的E_WARNING警告) 1024 E_USER_NOTICE 自定义的提醒消息。像由使用PHP函数trigger_error(程序员E_NOTICE集)
2048 E_STRICT 编码标准化警告。容许PHP建议修改代码以确保最佳的互操做性向前兼容性。 4096 E_RECOVERABLE_ERROR 开捕致命错误。像E_ERROR,但能够经过用户定义的处理捕获(又见set_error_handler()) 8191 E_ALL 全部的错误和警告(不包括 E_STRICT) (E_STRICT will be part of E_ALL as of PHP 6.0) 16384 E_USER_DEPRECATED 30719 E_ALL
推荐博文:http://www.cnblogs.com/zyf-zhaoyafei/p/3649434.html
3、PHP中的错误处理机制
set_error_handler函数接管PHP错误处理,也可使用trigger_error函数主动抛出一个错误。
set_error_handler(error_function, error_types)
设置用户自定义的错误处理函数。函数用于建立运行期间的用户本身的错误处理方法。它须要先建立一个错误处理函数,而后设置错误级别。
参数描述:
error_function($errno, $errstr, $errfile, $errline):规定发生错误时运行的函数。必须。用户的函数须要接受两个参数:错误码和描述错误的 string。另外有可能提供三个可选参数:发生错误的文件名、发生错误的行号 以及发生错误的上下文(一个指向错误发生时活动符号表的 array。
支持多种调用:
<?php // 直接传函数名 NonClassFunction set_error_handler('function_name'); // 传 class_name && function_name set_error_handler(array('class_name', 'function_name')); ?>
error_type:规定在哪一个错误报告级别会显示用户定义的错误。可选。默认是 E_ALL | E_STRICT。
注意:使用该函数会彻底绕过标准PHP错误处理函数(error_reporting(),包括@符),若是有必要,用户定义的错误处理程序必须终止(die())脚本。若是在脚本执行前发生错误,因为那时自定义程序尚未注册,所以不会用到这个自定义错误处理程序。因此通常定义在开头。且如下级别的错误不能由用户定义的函数来处理:E_ERROR
、 E_CORE_ERROR
、 E_CORE_WARNING
、 E_COMPILE_ERROR
、 E_COMPILE_WARNING
, E_PARSE
、和在调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT
。 只能捕获系统产生的一些Warning、Notice、Deprecated级别的错误。
能够在同一个页面使用restore_error_handler()函数取消自定义函数的接管。
register_shutdown_function(),此函数会在PHP程序终止或者die()时触发一个函数,给PHP一个短暂的回光返照。捕获PHP的错误:Fatal Error、Parse Error等
error_get_last();这个函数能够拿到本次执行产生的全部错误。error_get_last();返回数组的信息:
[type] - 错误类型
[message] - 错误消息
[file] - 发生错误所在的文件
[line] - 发生错误所在的行
set_exception_handler(),设置默认的异常处理程序,用在没有用try/catch块来捕获的异常,也就是说无论你抛出的异常有没有人捕获,若是没有人捕获就会进入到该方法中,而且在回调函数调用后异常会停止。
<?php error_reporting(0); echo '<pre>'; register_shutdown_function('myShutDown'); set_error_handler('myError'); set_exception_handler('myException'); function myError($code, $msg, $file, $line) { var_dump(compact('code', 'msg', 'file', 'line')); } function myShutDown() { $data = error_get_last(); if(is_null($data)){ var_dump('nothing error'); } else { var_dump('error',$data); } } function myException($e) { var_dump('myException:'.$e->getMessage()); } // require 'a.php'; // throw new Exception("throw exception", 1); // trigger_error('throw-error', E_USER_ERROR); try{ fun(); }catch(Exception $e){ var_dump('Exception:'.$e->getMessage()); }catch(Throwable $e){
// php7
var_dump('Throable:'.$e->getMessage()); }finally{ var_dump('finally'); }
类比 thinkphp5.1 中的错误处理机制:
public static function register() { error_reporting(E_ALL); set_error_handler([__CLASS__, 'appError']); set_exception_handler([__CLASS__, 'appException']); register_shutdown_function([__CLASS__, 'appShutdown']); } /** * Error Handler * @access public * @param integer $errno 错误编号 * @param integer $errstr 详细错误信息 * @param string $errfile 出错的文件 * @param integer $errline 出错行号 * @throws ErrorException */ public static function appError($errno, $errstr, $errfile = '', $errline = 0) { $exception = new ErrorException($errno, $errstr, $errfile, $errline); if (error_reporting() & $errno) { // 将错误信息托管至 think\exception\ErrorException throw $exception; } self::getExceptionHandler()->report($exception); } /** * Exception Handler * @access public * @param \Exception|\Throwable $e */ public static function appException($e) { if (!$e instanceof \Exception) { $e = new ThrowableError($e); } self::getExceptionHandler()->report($e); if (PHP_SAPI == 'cli') { self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); } else { self::getExceptionHandler()->render($e)->send(); } } /** * Shutdown Handler * @access public */ public static function appShutdown() { if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) { // 将错误信息托管至think\ErrorException $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); self::appException($exception); } // 写入日志 Container::get('log')->save(); }
demo:
a.php内容: <?php // 模拟Fatal error错误 //test(); // 模拟用户产生ERROR错误 //trigger_error('zyf-error', E_USER_ERROR); // 模拟语法错误 var_dump(23+-+); // 模拟Notice错误 //echo $f; // 模拟Warning错误 //echo '123'; //ob_flush(); //flush(); //header("Content-type:text/html;charset=gb2312"); b.php内容: <?php error_reporting(0); register_shutdown_function('zyfshutdownfunc'); function zyfshutdownfunc() { if ($error = error_get_last()) { var_dump('<b>register_shutdown_function: Type:' . $error['type'] . ' Msg: ' . $error['message'] . ' in ' . $error['file'] . ' on line ' . $error['line'] . '</b>'); } } set_error_handler('zyferror'); function zyferror($type, $message, $file, $line) { var_dump('<b>set_error_handler: ' . $type . ':' . $message . ' in ' . $file . ' on ' . $line . ' line .</b><br />'); } require 'a.php';
通常在生产环境下推荐修改php.ini error_report(0)。
display_errors
错误回显,通常经常使用语开发模式,可是不少应用在正式环境中也忘记了关闭此选项。错误回显能够暴露出很是多的敏感信息,为攻击者下一步攻击提供便利。推荐关闭此选项。 一旦某个产品投入使用,那么第一件事就是应该将display_errors选项关闭,以避免由于这些错误所透露的路径、数据库链接、数据表等信息而遭到黑客攻击。
1 # vim /etc/php.inidisplay_errors = Off 2 log_errors = On 3 error_log = /var/log/php-error.log
PHP.ini中display_errors = Off失效的解决
问题: PHP设置文件php.ini中明明已经设置display_errors = Off,可是在运行过程当中,网页上仍是会出现错误信息。
解决: 经 查log_errors= On,据官方的说法,当这个log_errors设置为On,那么必须指定error_log文件,若是没指定或者指定的文件没有权限写入,那么照样会输 出到正常的输出渠道,那么也就使得display_errors 这个指定的Off失效,错误信息仍是打印了出来。因而将log_errors = Off,问题就解决了。
4、PHP7对异常机制的改进
PHP7实现了一个全局的Throwable接口,原来的Exception和部分Error都实现了这个接口,以接口的方式定义了异常的继承结构。如今大多数的错误会被当作Error异常抛出,但仍是不够完善,只有部分错误实现了Throwable接口。
这种Error异常能够像Exception异常被第一个匹配的try/catch块捕获。若是没有匹配的catch块,则调用异常处理函数(set_exception_handler)进行处理。若没有注册此函数,则按传统的方式处理。
<?php try { test(); } catch(Throwable $e) { echo $e->getMessage() . ' zyf'; } try { test(); } catch(Error $e) { echo $e->getMessage() . ' zyf'; }