错误处理
错误报告级别
调整错误报告级别
- 可以通过在配置文件php.ini中,修改配置指令error_reporting的值,修改成功后重新启动Web服务器,则每个PHP脚本都可以按调整后的错误报告。下面是修改php.ini配置文件的示例。列出几种为error_reporting指令设置不同级别的值的方式,可以把位运算符[&(与)、|(或)、~(非)]和错误级别常量一起使用。
1
2
3
4
5
6
|
;可以抛出任何非注意的错误,默认值
error_reporting = E_ALL &~ E_NOTICE
;只考虑致命的运行时错误、解析错误和核心错误
error_reporting = E_ERROE | E_PARSE | E_CORE_ERROR
;报告除用户导致的错误之外的所有错误
error_reporting = E_ALL &~(E_USER_ERROR | E_USER_WARNING |E_USER_NOTICE)
|
- 或者在php脚本中使用error_reporting()函数,基于各个脚本来调整这种行为。这个函数用于确定php应该在特定的页面内报告哪些类型的错误。该函数获取一个数字或错误级别常量作为参数。
1
2
3
|
error_reporting(0); //设置为0会完全关闭错误报告
error_reporting(E_ALL); //将会向PHP报告发生的每个错误
error_reporting(E_ALL & ~ E_NOTICE); //可以抛出任何非注意的错误报告
|
使用trigger_error()函数来替代die()
自定义错误处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<?php
error_reporting
(0);
//屏蔽程序中的错误
/**
定义Error_Handler函数,作为set_error_handler()函数的第一个参数"回调"
@param int $error_level 错误级别
@param string $error_message 错误信息
@param string $file 错误所在文件
@param int $lin 错误所在行数
*/
function
error_handler(
$error_level
,
$error_message
,
$file
,
$line
) {
$EXIT
= FALSE;
switch
(
$error_level
) {
//提醒级别
case
E_NOTICE:
case
E_USER_NOTICE;
$error_type
=
'Notice'
;
break
;
//警告级别
case
E_WARNING:
case
E_USER_WARNING:
$error_type
=
'Warning'
;
break
;
//错误级别
case
E_ERROR:
case
E_USER_ERROR:
$error_type
=
'Fatal Error'
;
$EXIT
= TRUE;
break
;
//其他末知错误
default
:
$error_type
=
'Unknown'
;
$EXIT
= TRUE;
break
;
}
//直接打印错误信息, 也可以写文件,写数据库,反正错误信息都在这,任你发落
printf (
"<font color='#FF0000'><b>%s</b></font>: %s in <b>%s</b> on line <b>%d</b><br>\n"
,
$error_type
,
$error_message
,
$file
,
$line
);
//如果错误影响到程序的正常执行,跳转到友好的错误提示页面
if
(TRUE ==
$EXIT
) {
echo
'<script>location = "err.html"; </script>'
;
}
}
//这个才是关键点, 把错误的处理交给error_handler()
set_error_handler(
'error_handler'
);
//使用末定义的变量要报 notice 的
echo
$novar
;
//除以0要报警告的
echo
3/0;
//自定义一个错误
trigger_error(
'Trigger a fatal error'
, E_USER_ERROR);
|
- 系统直接报Fital Error这个方法是捕获不到的,遇到这种错误是必须解决的,所以系统会直接终止程序运行。
- E_ERROR、E_PARSE、E_CORE_ERROR、ERROR_WARNING/E_COMPILE_ERROR、ERROR_COMPILE_WARNING是不会被这个句柄处理的,也就是会用原始的方式显示出来。不过出现这些错误都是编译或PHP内核错误,在通常情况下不会发生。
- 使用set_error_handler()后,error_reporting()将会失效。也就是所有的错误都会交给自定义的函数处理。
写错误日志
如果使用自己指定的文件记录错误日志,一定要确保将这个文件存放在文档目录之外,以减少遭到攻击的可能。并且该文件一定要让PHP脚本的执行用户具有写权限。假设在linux操作系统中,将/usr/local/目录下的config文件作为错误日志文件,并设置Web服务器进程用户具有写的权限。然后在php的配置文件中,将error_log指令的值设置为这个错误日志文件的绝对路径。需要对php.ini中的配置指令做如下修改:
1
2
3
4
5
6
7
8
9
10
|
;将会向php报告发生的每个错误
error_reporting = E_ALL
;不显示满足上条指令所定义规则的所有错误报告
display_errors = Off
;决定日志语句记录的位置
log_errors =
On
;设置每个日志想的最大长度
log_errors_max_len = 1024
;指定产生的错误报告写入的日志文件位置
error_log = /usr/local/error.log
|
还可以使用php中的error_log()函数,送出一个用户自定义的错误信息。
1
|
bool error_log(stringmessage[,
int
message_type[,string destination[,string extra_headers]]])
|
第一个参数:必选项,即为要送出的错误信息。
第二个参数:为整数值,0表示送到操作系统的日志中;1则使用PHP的Mail()函数,发送信息到某Email地址处,第四个参数也会用到;2则将错误信息送到TCP服务器中,此时第三个参数destination表示目的地ip及Port;3则将信息存到文件destination中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
if(!Ora_Logon($username, $password)){
//将错误消息写入到操作系统日志中
error_log("Oracle数据库不可用!", 0);
}
if(!($foo=allocate_new_foo()){
//发送到管理员邮箱中
error_log("出现大麻烦了!", 1, "webmaster@www.mydomain.com");
}
//发送到本机对应5000端口的服务器中
error_log("搞砸了!", 2, "localhost:5000");
//发送到指定的文件中
error_log("搞砸了!", 3, "/usr/local/errors.log");
|
2、错误信息记录到操作系统的日志里
1
2
3
4
5
6
7
8
9
10
|
;将会向php报告发生的每个错误
error_reporting = E_ALL
;不显示满足上条指令所定义规则的所有错误报告
display_errors = Off
;决定日志语句记录的位置
log_erros = On
;设置每个日志项的最大长度
log_errors_max_len = 1024
;指定产生的错误报告写入操作系统的日志里
error_log = syslog
|
php还允许想系统syslog中发送定制的消息,php为这个特性提供了需要一起使用的4个专用函数。
- define_syslog_variables()
使用openlog()、syslog()及closelog()三个函数之前必须先调用该函数,因为在调用该函数时,他会根据现在的系统环境为下面三个函数初使用化一些必需的常量。
- openlog()
打开一个和当前系统中日志器的连接,为向系统插入日志消息做好准备。并将提供的第一个字符串参数插入到每个日志消息中,该函数还需要指定两个将在日志上下文使用的参数。
- syslog()
该函数向系统日志中发送一个定制消息。需要两个必选参数,第个参数通过指定一个常量定制消息的优先级。第二个参数则是像系统日志中发送定制的消息,需要提供一个消息字符串,也可以是php引擎在运行时提供的错误字符串。
- closelog()
1
2
3
4
5
6
7
|
<?php
define_syslog_variables();
openlog(
"PHP5"
, LOG_PID , LOG_USER);
syslog(LOG_WARNING,
"警告报告向syslog中发送的演示,警告时间:"
.
date
(
"Y/m/d H:i:s"
));
closelog
();
|
异常处理
异常处理实现
在php中,异常必须手动抛出。throw关键字将触发异常处理机制,他是一个语言结构,而不是一个函数,但必须给它传递一个对象作为值。如果在try语句中游艺场对象被抛出,改代码块不会再继续向下执行,而直接转到catch中执行。并传给catch代码块一个对象,也可以理解为被catch代码块不活的对象,其实就是导致异常常被throw语句抛出的对象。
扩展php那只的异常处理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<?php
/* 自定义的一个异常处理类 ,但必须是扩展内异常处理类的子类 */
class
MyException
extends
Exception{
//重定义构造器是第一个参数message变为必须被指定的属性
public
function
__construct(
$message
,
$code
=0){
//可以在这里定义一些自己的代码
//建议同时调用parent::construct()来检查所有的变量是否已被赋值
parent::__construct(
$message
,
$code
);
}
//重写父类方法,自定义字符串输出的样式
public
function
__toString(){
return
__CLASS__
.
":["
.
$this
->code.
"]"
.
$this
->message.
"<br/>"
;
}
//为这个异常自定义一个处理方法
public
function
customFunction(){
echo
"按自定义的方法处理出现的这个类型的异常<br/>"
;
}
}
try
{
$error
=
"允许抛出这个错误"
;
throw
new
MyException(
$error
);
echo
'Never executed'
;
}
catch
(MyException
$e
) {
echo
'捕获异常:'
.
$e
;
$e
->customFunction();
}
echo
"你好!"
;
|
捕获多个异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
<?php
/* 自定义的一个异常处理类,但必须是扩展内异常处理类的子类 */
class
MyException
extends
Exception{
//重定义构造器使第一个参数 message 变为必须被指定的属性
public
function
__construct(
$message
,
$code
=0){
//可以在这里定义一些自己的代码
//建议同时调用 parent::construct()来检查所有的变量是否已被赋值
parent::__construct(
$message
,
$code
);
}
//重写父类中继承过来的方法,自定义字符串输出的样式
public
function
__toString() {
return
__CLASS__
.
":["
.
$this
->code.
"]:"
.
$this
->message.
"<br>"
;
}
//为这个异常自定义一个处理方法
public
function
customFunction() {
echo
"按自定义的方法处理出现的这个类型的异常"
;
}
}
/* 创建一个用于测试自定义扩展的异常类MyException */
class
TestException {
public
$var
;
//用来判断对象是否创建成功的成员属性
function
__construct(
$value
=0) {
//通过构造方法的传值决定抛出的异常
switch
(
$value
){
//对传入的值进行选择性的判断
case
1:
//传入参数1,则抛出自定义的异常对象
throw
new
MyException(
"传入的值“1” 是一个无效的参数"
, 5);
break
;
case
2:
//传入参数2,则抛出PHP内置的异常对象
throw
new
Exception(
"传入的值“2”不允许作为一个参数"
, 6);
break
;
default
:
//传入参数合法,则不抛出异常
$this
->
var
=
$value
;
break
;
//为对象中的成员属性赋值
}
}
}
/* 示例1,在没有异常时,程序正常执行,try中的代码全部执行并不会执行任何catch区块 */
try
{
$testObj
=
new
TestException();
//使用默认参数创建异常的测试类对象
echo
"***********<br>"
;
//没有抛出异常这条语句就会正常执行
}
catch
(MyException
$e
){
//捕获用户自定义的异常区块
echo
"捕获自定义的异常:$e <br>"
;
//按自定义的方式输出异常消息
$e
->customFunction();
//可以调用自定义的异常处理方法
}
catch
(Exception
$e
) {
//捕获PHP内置的异常处理类的对象
echo
"捕获默认的异常:"
.
$e
->getMessage().
"<br>"
;
//输出异常消息
}
var_dump(
$testObj
);
//判断对象是否创建成功,如果没有任何异常,则创建成功
/* 示例2,抛出自定义的异常,并通过自定义的异常处理类捕获这个异常并处理 */
try
{
$testObj1
=
new
TestException(1);
//传1时,抛出自定义异常
echo
"***********<br>"
;
//这个语句不会被执行
}
catch
(MyException
$e
){
//这个catch区块中的代码将被执行
echo
"捕获自定义的异常:$e <br>"
;
$e
->customFunction();
}
catch
(Exception
$e
) {
//这个catch区块不会执行
echo
"捕获默认的异常:"
.
$e
->getMessage().
"<br>"
;
}
var_dump(
$testObj1
);
//有异常产生,这个对象没有创建成功
/* 示例2,抛出内置的异常,并通过自定义的异常处理类捕获这个异常并处理 */
try
{
$testObj2
=
new
TestException(2);
//传入2时,抛出内置异常
echo
"***********<br>"
;
//这个语句不会被执行
}
catch
(MyException
$e
){
//这个catch区块不会执行
echo
"捕获自定义的异常:$e <br>"
;
$e
->customFunction();
}
catch
(Exception
$e
) {
//这个catch区块中的代码将被执行
echo
"捕获默认的异常:"
.
$e
->getMessage().
"<br>"
;
}
var_dump(
$testObj2
);
//有异常产生,这个对象没有创建成功
|
错误查询
error_get_last():
函数获取最后发生的错误。
该函数以数组的形式返回最后发生的错误。
返回的数组包含 4 个键和值:
- type:错误类型。
- message:错误消息。
- file:发生错误所在的文件。
- line:发生错误所在的行。