PHP 错误处理

来源:互联网 发布:网络巡更系统 编辑:程序博客网 时间:2024/05/17 04:55
一.PHP错误类型
1.语法错误
2.环境错误
3.逻辑错误

二、错误级别:
错误常量:http://php.net/manual/zh/errorfunc.constants.php
1.E_DEPRECATED 8192
运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。
如在php5以上
if(ereg('hello','hello wrold!',$match)){
print_r($match);
}else{
echo 'NOT FOUND';
}

Deprecated: Function ereg() is deprecated
可以改写为:if(preg_match('/hello/i','hello world',$match))

2.E_NOTICE 8
运行时通知。表示脚本遇到可能会表现为错误的情况,但是在可以正常运行的脚本里面也可能会有类似的通知。但程序可继续向下执行

如:输出一个未定义的变量
echo $name
Notice: Undefined variable: undefinde 

如$users = array('name'=>'lilei');
echo $users[name];
Notice: Use of undefined constant name - assumed 'name'


3.E_WARNING (integer) 2
运行时警告 (非致命错误)。仅给出提示信息,但是脚本不会终止运行。
settype($var,'int');//settype 设置变量的类型
var_dump($var); //int(0)
settype($var,'int1');
var_dump($var);
Warning: settype(): Invalid type

4.E_ERROR (integer) 1
致命的运行时错误。这类错误一般是不可恢复的情况,例如内存分配导致的问题。后果是导致脚本终止不再继续运行。
如调用一个没有定义的函数
md6('123456');
 Fatal error: Call to undefined function md6()

5.E_PARSE (integer) 4、
编译时语法解析错误。解析错误仅仅由分析器产生。
如语句结束没有分号
Parse error: syntax error, unexpected end of file in

6.E_USER_ERROR
用户产生的错误信息
产生一个用户级别的 error/warning/notice 信息
trigger_error("Cannot divide by zero", E_USER_ERROR);
 Fatal error: Cannot divide by zero in 

三、PHP配置文件与错误相关选项
1.error_reporting设置错误级别
php.int 中
error_reporting = E_ALL
E_ALL & ~E_NOTICE (Show all errors, except for notices)
可以用位运算错误级别

display_error 是否显示错误 部署到线上时关闭
在php.ini中display_errors = On



2.error_reporting()函数设置错误级别
// 关闭所有PHP错误报告
error_reporting(0);
// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// 报告 E_NOTICE也挺好 (报告未初始化的变量
// 或者捕获变量名的错误拼写)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
// 除了 E_NOTICE,报告其他所有错误
error_reporting(E_ALL ^ E_NOTICE);
// 报告所有 PHP 错误 
error_reporting(E_ALL);或error_reporting(-1)

3.ini_set()函数运行时设置php.ini中错误级别
ini_set('error_reporting', E_ALL);

@错误抑制符

<?php
/*
* 用户自定义的错误
*/
header("content-type:text/html;charset=utf-8");
//报所有的错误
//error_reporting(-1);
//报告非通知错误
//error_reporting(E_ALL & ~ E_NOTICE);
//ini_set("error_reporting",E_ALL & ~ E_NOTICE);
ini_set("display_errors",1);

$a = 1;
$b = '2ab';
if(is_numeric($a) && is_numeric($b)) {
echo $a+$b;
}
else
{

//Warning
trigger_error("这是用户定义的警告!",E_USER_WARNING);
//Notice
trigger_error("这是用户定义的提示!:",E_USER_NOTICE);

//Fatal error 是致命级别的,所以不会向下执行
trigger_error("这是用户定义的错误!",E_USER_ERROR);
}



四、错误纪录
log_errors = On // 是否要记录错误日志log_errors_max_len = 1024 // 错误日志的最大长度ignore_repeated_errors = Off // 是否忽略重复的错误track_errors = Off // 是否使用全局变量$php_errormsg来记录最后一个错误xmlrpc_errors = 0 //是否使用XML-RPC的错误信息格式记录错误xmlrpc_error_number = 0 // 用作 XML-RPC faultCode 元素的值。html_errors = On // 是否把输出中的函数等信息变为HTML链接docref_root = http://manual/en/ // 如果html_errors开启了,这个链接的根路径是什么fastcgi.logging = 0 // 是否把php错误抛出到fastcgi中
1.将错误保存到指定文件中
log_errors = On
error_log = G:\error
或用函数error_log
error_log($msg)//会保存到配置中的error_log = F:/errors

<?php
/*
* 错误保存到指定的文件中
*/
//设置时区,日志保存的有时间
ini_set('date.timezone','PRC');
error_reporting(-1);
//这里设置显示错误与否都没关系
ini_set("display_errors","ON");

//开启错误日志
ini_set("log_errors","ON");
//指定保存到哪,文件夹一定要存在,可写的
ini_set("error_log","F:/errors/error.log");
echo $a;


2.将错误保存到系统日志中
log_errors = On
error_log = syslog
查看系统日志:右键计算机----->管理------>事件查看器

openlog('PHP5.4.0',LOG_PID,LOG_SYSLOG);
syslog(LOG_ERR,$msg);
closelog();

3.将错误发邮件
error_log — 发送错误信息到某个地方
bool error_log ( string $message [, int $message_type = 0 [, string $destination [, string$extra_headers ]]] )
如:
    error_log("Big trouble, we're all out of FOOs!", 1,
               "operator@example.com");

五、自定义错误日志
set_error_handler();
1.创建错误处理函数
2.设置不同的级别调用函数
3.set_error_handler()指定接管错误处理


<?php
/*
* 自定义错误处理函数,
* 如果使用set_error_handler()就不会用PHP内置的错误处理,除非回调函数返回的false
* set_error_handler()
*/
header("content-type:text/html;charset:utf-8");
error_reporting(-1);//不使用这个内置的处理对应级别的错误
function handler($errno,$errstr,$errfile,$errilne,$errcontext)
{
echo "错误代码:".$errno."<br/>";
echo "错误信息:".$errstr."<br/>";
echo "错误所在文件:".$errfile."<br/>";
echo "错误行号:".$errilne."<br/>";
echo "错误上下文:"."<br>";
//那么就会调用内置的错误处理
//return false;//如果返回fasle,

}

set_error_handler("handler",-1);
trigger_error("这是一个致命错误",E_USER_ERROR);
echo "continue...";
restore_error_handler();//取消接管,使用系统内置错误
//再次接管错误处理
//set_error_handler("handler",-1);
trigger_error("这是一个致命错误2",E_USER_ERROR);
echo "continue...";//系统内置对致命错误不处理
?>

错误代码:256
错误信息:这是一个致命错误
错误所在文件:F:\test\error3.php
错误行号:22
错误上下文:
continue...
( ! ) Fatal error: 这是一个致命错误2 in F:\test\error3.php on line 25
Call Stack
#
Time
Memory
Function
Location
1
0.0040
131504
{main}( )
...\error3.php:0
2
0.0040
131912
trigger_error ( )
...\error3.php:25


错误处理器:
<?php
class ErrorHandler{
private $errmsg;
private $errfile;
private $errline=0;
private $errcontxt=array();
private $noticelog = 'F:/errors/notice.log';
private $warnlog = 'F:/errors/warn.log';
private $errorlog = 'F:/errors/error.log';

public function __construct($errmsg,$errfile,$errline,$errcontxt)
{
$this->errmsg = $errmsg;
$this->errfile = $errfile;
$this->errline = $errline;
$this->errcontxt = $errcontxt;
}

public static function deal($errno,$errmsg,$errfile,$errline,$errcontxt)
{
$self = new self($errmsg,$errfile,$errline,$errcontxt);
switch ($errno){
case E_USER_ERROR:
//case E_ERROR: //这种类型的错误,是错误处理器不能管控的,只能靠系统内置的错误处理
$self->dealEror();
break;
case E_WARNING:
case E_USER_WARNING:
$self->dealWarn();
break;
case E_USER_NOTICE:
case E_NOTICE:
$self->dealWarn();
break;
default:
return false;
}

}

public function dealEror()
{
ob_start();
debug_print_backtrace();
$backtrace = ob_get_contents();
ob_end_clean();
$errormsg = <<<EOF
出现了致命错误,如下:
产生错误的信息:{$this->errmsg}
产生错误的文件:{$this->errfile}
产生错误的行号:{$this->errline}
追踪信息:{$backtrace}
EOF;
//error_log($errormsg,1,"458083770@qq.com");
error_log($errormsg,3,$this->errorlog);
exit(1);//终止程序
}

public function dealWarn()
{
$errormsg = <<<EOF
出现了警告错误,如下:
产生警告的信息:{$this->errmsg}
产生警告的文件:{$this->errfile}
产生警告的行号:{$this->errline}
EOF;

//error_log($errormsg,1,"458083770@qq.com");
error_log($errormsg,3,$this->warnlog);
}

public function dealNotice()
{
$datetime = date("Y-m-d H:i:s",time());
$errormsg = <<<EOF
出现了警告错误,如下:
产生通知的信息:{$this->errmsg}
产生通知的文件:{$this->errfile}
产生通知的行号:{$this->errline}
产生通知的时间:{$datetime}
EOF;
error_log($errormsg,3,$this->log);
}

}

//测试代码
error_reporting(-1);
set_error_handler(array('ErrorHandler','deal'));

echo $name;
trigger_error("this is user_error",E_USER_ERROR);
echo "continue....";//怕个不会执行,因为dealEror()中exit(1),使程序结束




六,对于 E_ERROR处理
如果程序中遇到这种至命错误,不想让用户看到这种错误
register_shutdown_function()

功能:register_shutdown_function() 函数可实现当程序执行完成后执行的函数,其功能为可实现程序执行完成的后续操作。程序在运行的时候可能存在执行超时,或强制关闭等情况,但这种情况下默认的提示是非常不友好的,如果使用register_shutdown_function()函数捕获异常,就能提供更加友好的错误展示方式,同时可以实现一些功能的后续操作,如执行完成后的临时数据清理,包括临时文件等。

可以这样理解调用条件:
1、当页面被用户强制停止时
2、当程序代码运行超时时
3、当PHP代码执行完成时,代码执行存在异常和错误、警告

<?php
class Shutdown
{
public function endScript()
{
if(error_get_last())
{
echo '<pre>';
print_r(error_get_last());
echo '</pre>';
}
//这个一定要是绝对路径,因为从内存中调用的
file_put_contents("F:/errors/test.log","this is test");
die("end script");
}
}
ini_set("display_errors","off");//不显示错误
register_shutdown_function(array(new Shutdown,"endScript"));
md6();