php地址解释错误,PHP错误和异常处理详解

前言:

关于PHP的错误和异常我准备用四大块来说明,内容如下:

一、错误与异常的

区别

异常一般指非语法和编译上的错误,指不符合程序预期,业务与流程上的错误,叫异常。

错误一般指PHP本身的报错,比如语法错误、环境错误等。根据错误类型区分错误级别,并且不能被try-catch捕获。

例:如下是一个PHP代码,其中有两个错误,echo xx,没加引号和分号。

try

{

echo xx

}catch (Execption $e)

{

echo $e->getMessage();

}

// 结果

// Parse error: syntax error, unexpected '}', expecting ',' or ';' in E:\work\app\phptest\index.php on line 5

由此可见PHP遇见本身的错误会直接触发一个错误,而不是异常,通过异常无法自动捕获错误。

二、错误处理

在PHP中的异常机制是不完善的,有些时候必须经过处理才能抛出异常,这样相当麻烦,所以我们可以采用自定义函数来接管PHP原生的报错。

1.错误配置指令

开启PHP错误

全局:在PHP配置文件中,display_errors = on/off;

局部:在程序中输入,ini_set("display_error", true/false);

注:log_errors = On情况下,必须制定error_log文件,如果指定地址错误或没有权限则会导致display_errors = Off失效,错误正常打印出来。

首先先了解下错误等级

级别

描述

E_ALL

所有错误和警告(不包括E_STRICT错误)

E_COMPILE_ERROR

致命的编译错误

E_COMPILE_WARNING

编译时警告

E_CORE_ERROR

PHP启动时发生的错误

E_CORE_WARNING

PHP启动时的警告

E_DEPRECATED

使用PHP将在未来版本中移除的特性

E_ERROR

致命的运行错误

E_NOTICE

运行时注意的消息

E_PARSE

编译时解析错误

E_RECOVERABLE_ERROR

几近致命的错误

E_STRICT

PHP版本可移植性建议

E_USER_DEPRECATED

用户使用PHP将在未来版本中移除的特性

E_USER_ERROR

用户导致的错误

E_USER_NOTICE

用户导致的注意消息

E_USER_WARNING

用户导致的警告

E_WARNING

运行时警告

这些等级的作用

在开发阶段,希望报告的所有错误。

在配置文件中,设置error_reporting = E_ALL & E_STRICT,表示显示所有错误。

error_reporting = E_ERROR | E_PARSE | E_CORE_ERROR,表示只考虑致命的运行时错误、解析错误和核心错误。

error_reporting = E_ALL & ~ E_USER_WARNING,表示不展示E_USER_WARNING错误。(~表示逻辑操作符NOT)

其他配置

display_startup_errors = On/Off ,表示显示PHP引擎初始化的所有错误。

error_log = On/Off,表示记录错误(日志)

log_errors = string,表示日志存放地址

log_errors_max_len = int,表示每个日志项的最大长度,以字节为单位,默认1024字节,0表示不指定最大字节

ignore_repeated_errors = On/Off,表示忽略PHP在同一文件同一行上发生的重复错误消息。

ignore_repeated_source = On/Off 指令将使PHP忽略不同文件中或同一文件中不同行上发生的重复错误。

track_errors =On/Off 指令会使PHP在变量$php_errormsg中存储最近发生的错误消息。

2.记录日志

两种方式:(以Windows为例)

第一种记录到文件,

error_log = x:/php/php_errors.log,这种方式安全性较低,被攻击者发现可以轻易的浏览目标路径等。

微信图片_20190816172757.png

第二种方式记录到syslog,一种系统日志工具(Linux是syslog日志工具,Windows是Event Viewer),两者大体相同。

具体操作:

error_log = syslog

echo 1/0;

点击“开始→运行”,输入eventvwr,打开事件查看器。

微信图片_20190816173437.png

Linux日志查看暂不举例。

手动记录到syslog函数

// define_syslog_variables(); // 初始化syslog,5.3之后不需要此函数

openlog("CHP8", LOG_PID, LOG_USER);

syslog(LOG_WARNING, "cha");

closelog();

// CHP8[11876] cha

openlog(iden,option,facility)

iden:每一项开始的表示符。

option:使用哪些日志选项,多个用|区分,比如LOG_ODELAY | LOG_PID

其中:

LOG_CONS,如果写入syslog发生错误,则将输出发送到控制台。

LOG_NDELAY,立即打开与syslog的连接

LOG_ODELAY,直到提交第一条消息打开连接,这是默认值。

LOG_PERROR,将要记录的消息同时输出到syslog和标准错误

LOG_PID,每个消息记录进程ID

facility:记录程序属于哪一类,一般包括LOG_KERN、LOG_USER、LOG_MAIL、LOG_DAEMON、LOG_AUTH、LOG_LPR、LOG_LOCALN(LOG_LOCALN最后的N是从0-7的值),指定LOG_CRON消息将发送到cron日志,一般在crontab中执行PHP使用。通常使用LOG_USER。

syslog(priority, message)

priority:日志优先级,表示严重程度。参数如下:

LOG_EMERG,严重的系统问题,可能预示崩溃。

LOG_ALERT,必须立即解决的情况,可能危害系统完整性。

LOG_CRIT,紧急错误,可能导致服务器不可用。

LOG_ERR,一般错误。

LOG_WARNING,一般警告。

LOG_NOTICE,正常但值得注意的情况。

LOG_INFO,一般信息。

LOG_DEBUG,一般与调试相关信息。

message:错误内容。

三、异常处理

基本异常使用

try

{

if (1)

{

throw new Exception("index Exception!");

}

}catch(Exception $e)

{

echo $e->getFile() . $e->getLine() . $e->getMessage();

}

// E:\work\app\phptest\index.php6index Exception!

其中包括7个方法:

getCode(),返回传递给构造函数的错误代码。

getFile(),抛出异常文件名。

getLine(),抛出异常行号。

getMessage(),返回传递的消息。

getPrevious(),返回前一个异常。

getTrace(),返回一个数组,包括上下文的信息。

getTraceAsString(),同上,不过返回的是字符串。

2.扩展异常类

class MyException extends Exception

{

function __construct($language, $errorcode)

{

$this->language = $language;

$this->errorcode = $errorcode;

}

function getMessageMap()

{

$errors = [

'en' => ['file error', 'name error'],

'ch' => ['文件错误', '名字错误'],

];

return $errors[$this->language][$this->errorcode];

}

}

try

{

if (1)

{

throw new MyException("ch", 1);

}

}catch(MyException $e)

{

echo $e->getMessageMap();

}

// 结果

// 名字错误

但是这样的异常处理其实意义不大。

四、错误异常联用

接管PHP原生异常

用set_error_handler(error_function, error_type)函数自定义错误处理函数。

// 第一种

/*class MyErrorClass{

// 必须是静态

public static function MyError($number, $message, $file, $line)

{

print_r(['code' => $number, 'message' => $message, 'file' => $file, 'line' => $line]);

}

}

set_error_handler(['MyErrorClass', 'MyError']);*/

// 第二种

function MyError($number, $message, $file, $line)

{

print_r(['code' => $number, 'message' => $message, 'file' => $file, 'line' => $line]);

}

set_error_handler('myError');

try {

$a = 1 / 0;

} catch (Exception $e)

{

echo "0不能做被除数";

}

// 结果

// Array ( [code] => 2 [message] => Division by zero [file] => E:\work\app\phptest\index.php [line] => 23 )

由此可知,自定方法截取了错误,此时我们可以操作错误抛出异常。

注意三点:

若用该方法,则error_reporting()不能再使用。

此方法不能处理E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING级别错误,该函数只能捕获系统产生的一些Warning、Notice级别的错误。

在报错前需要先注册本函数。

2.执行结束返回错误数据

register_shutdown_function(exception_function)可捕获Fatal Error、Parse Error等错误。不如脚本错误、die、exit、异常等结束都会调用。通过它可以在脚本结束前发现执行是否有误。利用error_get_last()查看错误。

echo aaa;

register_shutdown_function('shutdown');

function shutdown()

{

// error_get_last()获取错误数组

if ($error = error_get_last())

{

echo "

";

print_r($error);

}

}

/*

Warning: Use of undefined constant aaa - assumed 'aaa' (this will throw an Error in a future version of PHP) in E:\work\app\phptest\index.php on line 8

aaa

Array

(

[type] => 2

[message] => Use of undefined constant aaa - assumed 'aaa' (this will throw an Error in a future version of PHP)

[file] => E:\work\app\phptest\index.php

[line] => 8

)

*/

用户自定义异常处理

set_exception_handler(exception_function)

function myException($exception)

{

echo "异常:" , $exception->getMessage();

}

set_exception_handler('myException');

throw new Exception('aa');

// 异常:aa

完整代码

class MyException extends Exception

{

function __construct($language, $errorcode)

{

$this->language = $language;

$this->errorcode = $errorcode;

}

function getMessageMap()

{

$errors = [

'en' => ['file error', 'name error'],

'ch' => ['文件错误', '名字错误'],

];

// 记录日志

openlog("PHP7.2", LOG_PID, LOG_USER);

syslog(LOG_CRIT, $errors[$this->language][$this->errorcode]);

return $errors[$this->language][$this->errorcode];

}

}

function MyError($number, $message, $file, $line)

{

$errorArray = ['code' => $number, 'message' => $message, 'file' => $file, 'line' => $line];

// code==2抛出异常

if ($errorArray['code'] == 2)

{

throw new MyException('ch', 1);

}

}

set_error_handler('myError');

try {

$a = 1 / 0;

} catch (MyException $e)

{

echo $e->getMessageMap();

}

你可能感兴趣的:(php地址解释错误)