一、PHP的异常和错误

异常:在程序运行中不符合预期的情况及与正常流程不同的情况。一种不正常的情况,就是按照正常逻辑不该出错,但任然出错的情况,这属于逻辑和业务流程的一种中断,而不是语法错误。PHP只有主动 throw 后,才能捕获异常(一般情况下是这样,也有一些异常PHP可以自动捕获)。

基础知识:https://www.cnblogs.com/cshaptx4869/p/11210837.html

错误:属于自身问题,是一种非法语法或环境问题导致,让编译器无法通过检查甚至无法运行的情况。(简单说就是使脚本运行不正常的情况)

基础知识:https://www.cnblogs.com/cshaptx4869/p/11216353.html

二、错误的级别

大致分为几类:

1、deprecated,最低级别的错误,表示“不推荐、不建议”。一般是由于使用不推荐的、过时的函数或语法造成的。虽不会影响PHP正常流程,但一般情况下建议修正。

2、notice,一般告诉你语法中存在不当的地方。如使用的变量未定义、数组索引是字符时没有加引号,php视为常量去查找,找不到再视为变量。

不影响PHP正常流程

3、warning,比较高的错误,在语法中出现很不恰当的情况下才报此错误,比如函数参数不匹配。这种级别的会导致得不到预期结果,故需要修改代码。

4、fetal error,致命错误,直接导致PHP流程终结,后面的代码不再执行。比如调用一个不存在的方法,此错误必须处理。

5、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

三、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_ERRORE_PARSE、 E_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_COMPILE_WARNING,和在调用 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选项关闭,以免因为这些错误所透露的路径、数据库连接、数据表等信息而遭到黑客攻击。

         On表示开启状态下,若出现错误,则报错,出现错误提示。 Off 表示关闭状态下,若出现错误,则提示:服务器错误。但是不会出现错误提示

  log_errors 
  在正式环境下用这个就行了,把错误信息记录在日志里。可以关闭错误回显。 某个产品投入使用后,将PHP的log_errors开启,默认是记录到WEB服务器的日志文件里,比如Apache的error.log文件。 当然也可以记录错误日志到指定的文件中。另外也可以设定error_log = syslog,使这些错误信息记录到操作系统的日志里。

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,问题就解决了。

四、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';
}

参考文档: https://www.cnblogs.com/zyf-zhaoyafei/p/6928149.html

PHP异常和错误的更多相关文章

  1. 《java中异常和错误》

    异常和错误的区别. 异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发 ...

  2. 拦截PHP各种异常和错误,发生致命错误时进行报警,万事防患于未然

    在日常开发中,大多数人的做法是在开发环境时开启调试模式,在产品环境关闭调试模式.在开发的时候可以查看各种错误.异常,但是在线上就把错误显示的关闭. 上面的情形看似很科学,有人解释为这样很安全,别人看不 ...

  3. 关于Java异常和错误的几个问题

    1.Java中什么是Exception? 异常是Java传达给你的系统和程序错误的方式. 在java中,异常功能是通过实现比如Throwable,Exception,RuntimeException之 ...

  4. SQL2008、SQL2013 执行Transact-SQL 语句或者批处理时发生了异常。错误5120

    附加数据库的时候遇到问题,问题描述如下: 附加数据库 对于 服务器"服务器名"失败.(Microsoft.SqlServer.Smo) 执行Transact-SQL 语句或者批处理 ...

  5. C#管理异常和错误

    C#管理异常和错误 1.try/catch捕捉异常的语句块,其中try{}中是写可能会出错的程序代码,catch{}中是抛出异常的代码:一个try后可以有多个catch. 2.异常采用继承层次结构进行 ...

  6. java 检查抛出的异常是否是要捕获的检查性异常或运行时异常或错误

    /** * Return whether the given throwable is a checked exception: * that is, neither a RuntimeExcepti ...

  7. 扩展Python模块系列(五)----异常和错误处理

    在上一节中,讨论了在用C语言扩展Python模块时,应该如何处理无处不在的引用计数问题.重点关注的是在实现一个C Python的函数时,对于一个PyObject对象,何时调用Py_INCREF和Py_ ...

  8. chrome console的使用 : 异常和错误的处理 – Break易站

    本文内容来自:chrome console的使用 : 异常和错误的处理 – Break易站 利用 Chrome DevTools 提供的工具,您可以修复引发异常的网页和在 JavaScript 中调试 ...

  9. python 全栈开发,Day30(纸牌游戏,异常和错误,异常处理)

    一.纸牌游戏                                                                                              ...

随机推荐

  1. 光圈,快门, 曝光,焦距, ISO,景深。

    光圈,快门, 曝光,焦距, ISO,景深. ISO(感光度)与图片质量 ISO -- 感光度,是一个曝光率极高的词,我们在超市买饼干的时候就可能会看见包装袋上写:本公司已通过ISO9001质量体系认证 ...

  2. 关于C++ return * this

    转自 :https://blog.csdn.net/u011846436/article/details/45222905 不废话,直接上例子,使用赋值构造函数解释为什么需要 return *this ...

  3. sitecore8.2 如何关闭性能计数器

    在Sitecore.config文件或补丁文件修改Counters.Enabled为false值,此key默认为true;然后再修改Sitecore.Tasks.CounterDumpAgent 时间 ...

  4. 中文编码错误,Error output could not be translated from the native locale to UTF-8.

    假如使用http访问仓库,用户配置的pre-commit钩子里面如果有中文,可能会出现"Error output could not be translated from the nativ ...

  5. 操作mongodb

    MongoDB数据库是以k-v形式存储在磁盘上的. import pymongoclient = pymongo.MongoClient(host='10.29.3.40',port=27017)db ...

  6. java线程学习之Sleep方法

    sleep方法是在线程中常用到的一个方法,它是一个静态方法. sleep(long millis)       在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度 ...

  7. 2.1JAVA基础复习——JAVA语言的基础组成注释和常量变量

    JAVA语言的基础组成有: 1.关键字:被赋予特殊含义的单词. 2.标识符:用来标识的符号. 3.注释:用来注释说明程序的文字. 4.常量和变量:内存存储区域的表示. 5.运算符:程序中用来运算的符号 ...

  8. jsp页面在Android系统和ISO系统的兼容性问题

    问题:一个jsp页面在Android手机上显示正常,但到了ISO系统上jsp页面的样式不显示了. 原因:css文件中设置样式时单位不兼容. 解决方案:将rem 转换成px;

  9. mtd-utils交叉编译安装

    一.获取源码并解压 存储于/home/zhangyi/work/psoc_ltp/tools-ltp-ddt中,解压后的源码存于上一层目录. 1.mtd-utils-2.0.0 wget ftp:// ...

  10. ELK学习笔记之ELK搜集OpenStack节点日志

    模板来自网络,模板请不要直接复制,先放到notepad++内调整好格式,注意缩进 部署架构 控制节点作为日志服务器,存储所有 OpenStack 及其相关日志.Logstash 部署于所有节点,收集本 ...