常见的错误和异常
拼写错误
- 常量和变量都是区分大小写的。函数名、方法名、类名不区分大小写,但建议使用与定义时相同的名字。
- 预定义常量不区分大小写,但是建议全部大写,包括
_LINE_、_FILE_、_DIR_、_FUNCTION_、_CLASS_、_METHOD_、_NAMESPACE_
。 - 编写代码输入中文字符后为切换回英文状态,导致输入符号的错误等等
单引号和双引号的混乱
- 单引号、双引号在PHP中没有特殊的区别,都可以用来创建字符串。双引号串中的内容可以被解释和替换,而单引号串中的内容总被认为是普通字符串
括号使用混乱
- 括号包含两种语义
- 分隔符
- 表达式
- 避免括号使用层次过多,缺少括号的方法为:先输入完整的括号,再在里面输入内容
等号与赋值混淆
- 一般出现在if条件判断语句中,在条件判断是否相等时,应该使用“==”运算符
缺少美元符号
- 在PHP中,设置变量时需要使用美元符号“$”,如果不添加美元符号,就会引起解析错误
调用不存在的常量和变量
- 如果调用没有声明的常量或者变量,就会触发NOTICE错误
调用不存在的文件
- 调用不存在文件,程序会直接停止运行并提示错误信息
环境配置的错误
- 环境配置不当;不同的操作系统采用不同的路径格式;不同的操作系统上的功能也会有差异;这些都有可能导致程序运行错误、
数据库服务器连接错误
- 由于PHP应用于动态网站的开发,所以经常会对数据库进行基本的操作。在操作系统之前,需要连接数据库服务,如果数据库出现错误,也会导致程序运行出现错误
错误处理
php.ini中的错误处理机制
- php.ini文件规定了错误的显示方式,包括配置选项的名称、默认值、表述的含义等。
- 常见的错误配置选项
- display_errors,默认值:On
- 设置错误作为PHP的一部分输出。开发过程中可以采用默认的设置,但是为了安全考虑,在生产环境中还是设置为Off比较好
- error_reporting,默认值:E_all
- 这个设置会显示所有的出错信息。这种设置会让一些无害的提示也显出出来,所以可以设置默认值为E_all&E_NOTICE,这样只会显示不良编码和错误
- error_log,默认值:null
- 设置记录错误日志的文件。在默认情况下将错误发送到Web服务器日志,用户也可以指定写入的文件
- html_errors,默认值:On
- 控制是否在错误信息中采用HTML格式
- log_errors,默认值:Off
- 控制是否应该将错误发送到主机服务器的日志文件
- display_startup_errors,默认值:Off
- 控制是否显示PHP启动时的错误
- track_errors,默认值:Off
- 设置是否保存最近一个警告或错误信息
- display_errors,默认值:On
应用DIE语句进行调试
- 使用DIE语句进行调试的优势是,不仅可以显示错误的位置,还可以输出错误信息,一旦出现错误,程序将会终止运行,并且在浏览器上显示出错之前的信息和错误信息
- 语法格式:die(“相关的错误信息”)
- 例如:
if(!file_exits("test.txt")){
die("文件不存在");
}else{
$file=fopen("test.txt","r");
}
自定义错误和错误触发器
- 创建一个专用函数,在PHP程序发生错误时调用该函数
- 自定义的错误函数的语法格式-
error_function(error_level,error_message,error_file,error_line,error_context)
- 该函数必须至少包含level和message参数,另外3个参数file、line和context是可选的
- 各个参数的具体含义
- error_level:为用户定义的错误规定错误报告级别,必须是一个值
- error_message:为用户定义的错误规定错误消息
- error_file:规定错误在其中发生的文件名
- error_line:规定错误发生的行号
- error_context:规定一个数组,包含了当错误发生时在使用的每个变量以及它们的值
- error_level具体的级别值
- 2:E_WARNING
- 非致命的run-time错误。不暂停脚本执行
- 8:E_NOTICE
- run-time通知。脚本发现可能有错误发生,但也可能在脚本正常运行时发生
- 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
- 4096:E_RECOVERABLE_ERROR
- 可捕获的致命错误。类似于E_ERROR,但可被用户定义的处理程序捕获
- 8191:E_ALL
- 所有错误和警告
- 2:E_WARNING
- 例如:
- 自定义的错误函数的语法格式-
function customError($errno,$errstr){
echo "<b>错误:</b> [$errno] $errstr <br />";
echo "终止错误";
die();
}
上述代码是一个简单的错误处理函数。当它被触发时,它会取得错误级别和错误消息。然后它会输出错误级别和消息,并终止程序
- 创建一个错误处理函数后,下面需要确定在何时触发该函数
- 使用set_error_handler()函数来设置用户自定义的错误处理函数。该函数用于创建运行期间的用户自己的错误处理方法,该函数会返回旧的错误处理程序,若失败,则返回null
- 语法格式
set_error_handler(error_function,error_types)
- 其中error_function为必需参数,规定发生错误运行的函数;error_type是可选参数,如果不选择此参数,则表示默认是为”E_ALL”
- 例如(接上例):
//定义错误函数
function customError($errno,$errstr){
echo "<b>错误:</b> [$errno] $errstr <br />";
}
//设置错误函数的处理
set_error_handler("customError");
//触发自定义错误函数
echo($test);
- 还可以使用trigger_error()函数创建用户自定义的错误消息
- 此函数用于在指定的条件下触发一个错误消息。它与内建的错误处理器一同使用,也可以与由ser_error_handler()函数创建的用户自定义函数一起使用。如果指定了一个不合法的错误类型,该函数返回false,否则返回true
- 语法格式
trigger_error(error_message,error_types)
- error_message为必需参数,规定错误消息,长度限制为1024个字符;error_types为可选参数,规定错误消息的错误类型,可能的值为E_USER_ERROR、E_USER_WARNING或者E_USER_NOTICE
- 使用trigger_error()函数示例:
$test=5;
if($test>4){
trigger_error("Value must be 4 or below");
}
- trigger_error()函数和自定义函数一起使用示例:
//定义错误函数
function customError($errno,$errstr){
echo "<b>错误:</b> [$errno] $errstr";
}
//设置错误函数的处理
set_handler("customError",E_USER_WARNING);
//trigger_error函数
$test=5;
if($test>4){
trigger_error("Value must be 4 or below",E_USER_WARNING);
}
错误记录
- 在默认情况下,根据php.ini的error_log配置,PHP向服务器的错误记录系统或文件发送错误记录。通过使用error_log()函数,用户可以向指定的文件或远程目的地发送错误记录
- 语法格式
error_log ( string $message [, int $message_type = 0 [, string $destination [, string $extra_headers ]]] )
- message为必需参数,表示错误信息;其它均为可选参数;message_type表示错误应该被发送的位置,默认为0;destination表示目标 ,含义由message_type决定;extra_headers为额外的头,具体含义见下
- message_type可选参数
- 0:message 发送到 PHP 的系统日志,使用 操作系统的日志机制或者一个文件,取决于 error_log 指令设置了什么
- 1:message 发送到参数 destination 设置的邮件地址。 第四个参数 extra_headers 只有在这个类型里才会被用到。
- 2:不再是一个选项。
- 3: message 被发送到位置为 destination 的文件里。 字符 message 不会默认被当做新的一行。
- 4: message 直接发送到 SAPI 的日志处理程序中。
- 以发送到邮箱为例:
function customError($errno,$errstr){
echo "<b>错误:</b> [$errno] $errstr";
error_log("错误:[$errno] $errstr <br/>",1,"email_name_receiver@example.com","From:email_name_sender@example.com")
echo "错误已经发送到邮箱";
}
错误的报告方式(PHP7新变化)
- PHP7改变了大多数错误的报告方式。不同于PHP5的传统错误报告机制,现在大多数错误被作为Error异常抛出
- 这种Error异常可以像普通异常一样被try/catch块进行捕获,如果没有匹配的try/catch块,则调用异常处理函数(set_exception_handler())进行处理。如尚未注册异常处理函数,则按照传统方式进行处理——被报告为一个致命错误
- Error类并不是Exception类扩展出来的,所以用
catch(Excecption $e) { ... }
这样的代码是捕获不到Error的。用户可以用catch(Error $e) { ... }
这样的代码。或者通过注册异常处理函数(set_exception_handler()
)来捕获Error
例如:
class Mathions
{
protected $n = 10;
//求余数运算,除数为0,抛出异常
public function dotion() : String
{
try{
$value= $this -> n %0;
return $value;
} catch(DivisionByZeroError $e){
return $e->getMessage();
}
}
$aa= new Mathtions();
print($aa ->dotion());
}
异常处理
异常的基本处理方法
- 异常处理用于在指定的错误(异常)情况发生时改变脚本的正常执行流程。
- 当异常发生时,通常会发生以下动作
- 当前代码状态被保存
- 代码执行被切换到预定义的异常处理器函数
- 根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行。或从代码中另外的位置继续执行脚本
- 当异常被抛出时,其后的代码不会被继续执行,PHP会尝试查找匹配的catch代码块。如果异常没有被捕获,而且又没有使用set_exception_handler()做相应的处理的话, 那么将发生一个严重的错误,并且输出Uncaught Exception(未捕获异常)的错误消息
- 处理异常的程序应当包括以下代码块
- try代码块
- 使用异常的函数应该位于try代码块内,如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常
- throw代码块
- 规定如何触发异常。每一个throw必须对应至少一个catch
- catch代码块
- catch代码块会捕获异常,并创建一个包含异常信息的对象
- try代码块
- 例如:
function checkNum($number){
if($number>1){
throw new Exception("数值必须小于或等于1");
}
return true;
}
try{
checkNum(2);
echo '没有任何异常';
}catch(Exception $e){
echo '异常信息:'.$e->getMessage();
}
自定义的异常处理器
- 创建一个专门的类,当PHP程序中发生异常时,调用该类的函数即可,该类必须是以Exception类的一个扩展
- 例如:
class customException extends Exception{
//错误消息
public function errorMessage(){
$errorMsg='异常发生的行:'.$this->getLine().' in ' .$this->getFile().'<b>'.$this->getMessage().'</b>不是一个有效的邮箱地址';
return $errorMsg;
}
}
$email="email_name@example.321com";
try{
//检查是否符合条件
if(filter_var($email,FILTER_VALIDATE_EMAIL)===FALSE){
//如果邮件地址无效,则抛出异常
throw new customException($email);
}
}catch(Exception $e){
//显示自定义的消息
echo $e->errorMessage();
}
处理多个异常
- 在上述范例中,只检查了邮箱地址是否有效。如果想检查邮箱是否为雅虎邮箱,或想检查是否有效等多种情况,可以使用if…else代码块,或者一个switch代码块,或者嵌套多个异常
设置顶层异常处理器
- 所有未捕获的异常都可以通过顶层异常处理器来处理。顶层异常处理器可以使用set_exception_handler()函数来实现。该函数设置自定义的异常处理函数,用于创建运行时期特定的异常处理方式。
- 语法格式
set_exception_handler(exception_function)
- exception_function为必须的参数,规定未捕获的异常发生时调用的函数,该函数必须在调用set_exception_handler()函数前定义。这个异常处理函数需要一个参数,即抛出的exception对象
- 例如:
function myException($exception){
echo "<b>异常时:</b>", $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('正在处理未被捕获的异常');
Some Tips
处理异常的原则
- 需要进行异常处理的代码应该放入try代码块内,以便捕获潜在的异常
- 每个try和throw代码块必须至少拥有一个对应的catch代码块
- 使用多个catch代码块可以捕获不同种类的异常
- 可以在try代码块内的catch代码块中再次抛出(re-throw)异常
如何隐藏错误信息
- 在调用的函数名前加@符号,这样会隐藏可能由于这个函数导致的错误信息
- 例如:
@$ab= fopen("123.txt","r");
@fclose();
- 如果指定的文件不存在,运行程序时就不会出现错误信息了