PHP错误处理

PHP错误处理

一、PHP错误分类

  • 不致命的:deprecated、notice、warning
  • 致命的:error、语法解析错误
  • 用户自定义的错误消息:trigger_error()

不致命的

1、deprecated 最低级别的错误

使用一些过期函数的时候会出现,程序将继续执行

例子:

$pattern = '[0-9]+';
$subject = 100;
//$int = preg_match($pattern,$subject);
$int = eregi($pattern,$subject);
var_dump($int);

preg_match($pattern,$subject)返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后将会停止搜索。如果发生错误preg_match()返回 FALSE。

2、notice 通知级别的错误

使用一些未定义变量、常量或者数组key没有加引号的时候出现

echo $a;      //打印一个未定义变量
echo string;  //string 会把当成常量
echo $array[name]; //name 会把当成常量

3、Warning 警告级别的错误

程序出问题,需要修改代码!也不影响程序继续执行

settype($var, 'init');//integer

致命的

1、fatal-error 致命级别的错误

程序报致命的错误,此时程序会在报错处终止程序继续执行

test('123');// 调用致命的错误
//Fatal error: Call to undefined function test()

2、parse error 语法解析错误

语法检查阶段报错,需要修改代码.属于高级的error错误,代码检查阶段中发现,不会执行代码!

echo 'nie ge'
//Parse error: syntax error, unexpected

用户自定义的错误

用户自定义的错误,用户手动抛出错误。由用户自己在代码中使用PHP函数 trigger_error() 来产生的。

header('content-type:text/html;charset=utf-8');
if ($divisor == 0) {
    trigger_error("Cannot divide by zero", E_USER_ERROR);
}//error_types取值E_USER_ERROR、E_USER_WARNING、E_USER_NOTICE(默认)

二、错误处理

错误处理就是提前做好准备,假如出现了错误,首先我们应该接收或是捕获到错误信息,然后给出错误处理方案,或写入日志、或发邮箱、或发短信等等;

1、显示或关闭错误信息

1、修改php.ini 开启 display_errors,需要重启服务器

display_errors = On

2、使用ini_set()函数 允许脚本临时覆盖(或叫动态修改)PHP配置文件中的设置

ini_set ('display_errors', 1);

2、设置合适的错误报告级别

错误级别和常数如下:

常量 说明
1 E_ERROR 报告导致脚本终止运行的致命错误
2 E_WARNING 报告运行时的警告类错误(脚本不会终止运行)
4 E_PARSE 报告编译时的语法解析错误
8 E_NOTICE 报告通知类错误,脚本可能会产生错误
2048 E_STRICT PHP5+,代码可以运行,但是php不建议这样写
32767 E_ALL 报告所有的可能出现的错误(不同的PHP版本,常量E_ALL的值也可能不同)

1、在php.ini配置文件里设置error_reporting级别

error_reporting = E_ALL & ~E_NOTICE(~不包括)

2、使用error_reporting()函数(动态修改)

error_reporting (0); //不需要报告任何错误 
error_reporting (E_ALL); //报告所有错误 
error_reporting (E_ALL & ~E_NOTICE); //除了notice以外报告所有

3、函数set_error_handler('自定义函数')

在报错时候,使用自己定义的函数来处理脚本中出现的错误,也就是使用我们自己定义的方式来处理运行中的错误。另外该函数只能接收到非致命的报错。

error_function(error_level,error_message,error_file,error_line,error_context)

该函数必须有能力处理至少两个参数 (error level 和 error message),但是可以接受最多五个参数(可选的:file, line-number 和 error context):

参数 描述
error_level 必需。为用户定义的错误规定错误报告级别。必须是一个数字。
error_message 必需。为用户定义的错误规定错误消息。
error_file 可选。规定错误发生的文件名。
error_line 可选。规定错误发生的行号。
error_context 可选。规定一个数组,包含了当错误发生时在用的每个变量以及它们的值。

如果在自定义函数中返回false,则会在自定义函数处理完后交由系统默认错误处理器处理

ini_set('display_errors',0);
$debug = 1; // 开启显示错误提醒
// 自定义错误处理函数
function myErrorHandler($e_number, $e_message, $e_file, $e_line, $e_vars)
{
    global $debug;
    $message = "脚本 <strong>{$e_file}</strong> 中出现错误在第<span style=\"color:red;\">{$e_line}</span>行: $e_message";

    if ($debug) {
       echo '<div style="width:90%;padding:10px;border:1px solid green;">' . $message . '</div>';
    }
}
set_error_handler('myErrorHandler');

4、函数error_log

error_log函数:专门用于日记记录。

  0:通过PHP标准的错误处理机制来记录;
  1:邮件发生到指定的地方;
  3:使用指定的文件记录错误报告日志

php.ini配置:

//将会向PHP报告发生的每个错误
error_reporting  =  E_ALL;

//不显示满足上条 指令所定义规则的所有错误报告
display_errors = Off;

//开关
log_errors = On;

//设置每个日志项的最大长度
log_errors_max_len = 1024 ;
//将错误记录到当前系统日志,默认使用Apache记录错误日志
error_log=syslog;

//指定产生的 错误报告写入的日志文件位置
error_log = /usr/local/errors.log;

5、register_shutdown_function()函数

register_shutdown_function()该函数是当页面程序停止运行的时候触发,并不是专门用来接收错误的。而页面终止运行的场景包括了:页面程序正常走完,程序中出现die/exit,或是页面抛了异常,还有就是出现了致命报错(除了语法解析)。通过这个函数就可以在脚本结束前判断这次执行是否有错误产生。这时就要借助于一个函数:error_get_last();

register_shutdown_function(function (){
    if(($error = error_get_last()) !== null) {
        // 处理报错,如果没有错误则返回 NULL。
    }
});

#demo();
if( 1 ){
    exit('hehe');
}

三、 语法解析错误问题

上面使用set_error_handleregister_shutdown_function均不能正常接收到语法解析的报错。原因是PHP的运行机制是,首先我们写的代码在运行前,PHP引擎会先进行语法的校验,如果语法没有问题,才会逐行执行我们的代码;所以假如我们代码中有语法错误,PHP引擎一开始就报错了,根本不会执行上面代码。
但是 我们可以借助引入文件来解决这问题,这也许也算是框架里使用主入口的其中一个好处吧。下面的例子里在demo.php页面里定义了错误处理,在引入文件other.php里出现了语法解析报错。

# demo.php
register_shutdown_function(function (){
    $error = error_get_last();
    if($error!==null){//处理错误
        date_default_timezone_set(PRC);
        $logInfo = date('Y-m-d H:i:s');
        $logInfo .= "文件:{$error['file']} ,在页面的第{$error['line']},报了一个{$error['type']},具体错误信息是:{$error['message']}";
        $dir = MESSAGE.DS.date('Y').DS.date('m').DS.date('d');
        if(!file_exists($dir)){
            mkdir($dir,0777,true);
        }
        file_put_contents($dir.DS.'error.log', $logInfo.PHP_EOL,FILE_APPEND);//路径需要写绝对路径
    }
});
include_once 'other.php';//出现语法错误

自定义错误完整实例

//关闭错误信息
ini_set ('display_errors', 0);
//报告所有级别错误
error_reporting (E_ALL);
//设置默认时区
date_default_timezone_set('PRC');
//设置日志路径
define("DS",DIRECTORY_SEPARATOR);//斜杠兼容性,linux路径用‘/’,windows用‘/’or‘\’都可以
define("LOGS_PATH",dirname(__FILE__).DS.'logs'.DS);
if(!file_exists(LOGS_PATH)){
    mkdir(LOGS_PATH,0777,true);
}
//设置自定义函数处理错误
set_error_handler(function($errno, $errstr, $errfile, $errline){
    $errArr=["1"=>"error","2"=>"warning","4"=>"parse error","8"=>"notice","2048"=>"strict","8192"=>"deprecated"];
    $date=date("Y/m/d H:i");
    $logsTemp="[%s] 【%s】 文件:%s有报错,错误出现在第%s行,错误详情:%s".PHP_EOL;
    $logs=sprintf($logsTemp,$date,$errArr[$errno],$errfile,$errline,$errstr);
    file_put_contents(LOGS_PATH.'error.log',$logs,FILE_APPEND);
});

//页面停止运行时候触发,处理致命错误
register_shutdown_function(function (){
    if(($err = error_get_last()) !== null) {
        // 处理报错
        $date=date("Y/m/d H:i");
        $logsTemp="[%s] 【error】 文件:%s有报错,错误出现在第%s行,错误详情:%s".PHP_EOL;
        $logs=sprintf($logsTemp,$date,$err['file'],$err['line'],$err['message']);
        file_put_contents(LOGS_PATH.'error.log',$logs,FILE_APPEND);
    }
});




posted @ 2021-09-05 19:51  成文的博客  阅读(83)  评论(0编辑  收藏  举报