文章目录
常见的错误和异常
-
拼写错误
PHP中常量和变量都是区分大小写的,如果将常量或变量名写错,将会得到一个**Notice**: Undefined variable:
提示。
PHP中的函数名、方法名、类名是不区分大小写的,但是建议使用与定义时相同的名字。
PHP中的魔术常量不区分大小写,但是建议全部大写。
另外,在编写代码过程中,由于输入法的原因,还容易导小括号,分号,引号等出现错误,因此要特别小心。 -
单引号和双引号混用
单引号、双引号在PHP中没有特殊区别,都可以用来创建字符串。但必须成对儿出现,另外缺少单引号或者双引号也是经常出现的问题。系统会抛出一个**Parse error**: syntax error,
错误。 -
括号使用混乱
当编写的代码括号的层次较多时容易出现缺少反括号的错误。系统会抛出一个**Parse error**: syntax error
错误 -
相等运算符与赋值符号混淆
在进行相等比较的时候容易产生此类错误。此类错误多数情况下不会抛出异常,但是会导致程序功能与开发者意图相悖。 -
缺少美元符号
在PHP中,设置变量时需要使用美元符号,如果不添加美元符号就会引起解析错误,**Parse error**: syntax error
-
调用不存在的常量和变量
调用没有声明的变量或常量,将会触发**NOTICE: Undefined variable**
错误。 -
调用不存在的文件
调用不存在的文件,将会触发**Warning**
错误。如:Warning: include(mybook.php): failed to open stream: No such file or directory Warning: include(): Failed opening 'mybook.php' for inclusion (include_path='.;C:\php\pear') in
-
环境配置错误
环境配置不当也会给运行带来错误,例如PHP配置文件和PHP的版本等,如果配置不正确,就会提示文件无法打开、操作权限不具备和服务器无法连接等错误信息。
错误处理
常见的错误处理方法包括使用错误处理机制、使用DIE语句调试、自定义错误和错误触发器等。
php.ini中的错误处理机制
php.ini文件规定了错误的显示方式,包括配置选项的名称、默认值和表述的含义等。常见的错误配置选项内容如下:
名称 | 默认值 | 含义 |
---|---|---|
display_errors | On | 设置错误作为PHP的一部分输出。开发的过程中可以采用默认的设置,但为了安全考虑,在生产环境中还是应设置为Off。 |
error_reporting | E_ALL | 这个设置会显示所有的出错信息。这种设置会让一些无害的提示也显示,所以可以设置error_reporting的默认值为error_reporting=E_ALL&~E_NOTICE,这样只会显示错误和不良编码 |
error_log | null | 设置记录错误日志的文件。默认情况下降错误发送到web服务器日志,用户也可以指定写入的文件 |
html_errors | On | 控制是否在错误信息中采用HTML格式 |
log_errors | Off | 控制是否应该将错误发送到主机服务器的日志文件 |
display_startup_errors | Off | 控制是否显示PHP启动时的错误 |
track_errors | Off | 设置是否保存最近一个警告或错误消息 |
应用DIE语句调试
使用DIE语句调试的优势是,不仅可以显示错误的位置,还可以输出错误信息。一点出现错误,程序会终止运行,并在浏览器上显示出出错之前的信息和错误信息。
【示例】
<?php
echo "这是程序出错之前的信息<br />";
if (!file_exists("test.txt")) {
die("文件不存在");
} else {
$file=fopen("test.txt");
}
echo "<br />这是程序出错之后的信息";
?>
程序输出结果:
可以看到,使用DIE语句调试在错误之后便终止了脚本执行。
自定义错误和错误触发器
用户可以通过创建专用函数error_function()
,来在PHP发生错误时调用该函数。该函数的语法格式如下:
error_function(error_level, error_message, error_file, error_line, error_context)
创建该函数必须至少包含error_level和error_message两个参数,函数各参数的含义如下:
- 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函数triger_error()设置的E_NOTICE |
4096 | E_RECOVERABLE_ERROR | 可捕获的执行错误,类似E_ERROR,但可被用户定义的处理程序捕获 |
8191 | E_ALL | 所有错误和警告 |
【示例】
<?php
// 首先自定义错误处理函数
function customError($errno, $errstr) {
echo "<b>错误:<b> [$errno] $errstr<br />";
echo "终止程序";
die();
}
// 然后使用set_error_handler()来设置自定义错误处理函数
// set_error_handler(error_function, error_types)
// error_types参数可选,默认为E_ALL
set_error_handler("customError");
// 触发自定义错误函数
echo($test);
?>
程序输出结果:
在脚本中用户输入数据的位置,当用户输入无效时触发错误。在PHP中,这个任务由trigger_error()
完成。
trigger_error()
函数创建用户自定义的错误消息。用于在用户指定的条件下触发一个错误消息。它与内建的错误处理器一同使用,也可以由set_error_handler()
函数创建的用户自定义函数一起使用。如果指定了一个不合法的错误类型,该函数返回false,否则返回true。
trigger_error()
函数的具体语法格式如下:
trigger_error(error_message, error_types)
其中,error_message参数为必需参数,定义错误消息,长度限制为1024个字符。error_types为可选参数,定义错误消息的错误类型,可能的值为E_USER_ERROR、E_USER_WARNING、E_USER_NOTICE。
【示例】
<?php
$test = 5;
if ($test > 4) {
// 创建自定义错误消息
trigger_error("value must be 4 or below");
}
?>
程序输出结果:
【示例2】
<?php
// 定义错误函数
function customError($errno, $errstr) {
echo "<b>错误:</b> [$errno] $errstr";
}
// 设置错误处理函数
set_error_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()
函数语法格式如下:
error_log(string $message[, int $message_type=0[, string $destination[, string $extra_headers]]]):bool
函数参数说明:
- message:应该被记录的错误消息。
- message_type:设置错误应该发送到何处。可能有以下信息类型:
- 0:发送到PHP的系统日志,使用操作系统的日志机制或者一个文件,取决于error_log指令设置了什么。这是默认选项。
- 1:发送到参数destination设置的邮件地址。第四个参数extra_headers只有在这个类型里才会被用到。
- 2:不再是一个选项
- 3:被发送到位置为destination的文件里。字符message不会默认被当做新的一行。
- 4:直接发送到SAPI的日志处理程序中。
- destination:目标。它的含义描述于以上,由message_type参数所决定。
- extra_headers:额外的头。当message_type设置为1时使用,该信息类型使用了
mail()
的同一个内置函数。
警告:error_log()并非二进制安全的。null字符可能截断。
【示例】
<?php
// 定义错误函数
function customError($errno, $errstr) {
echo "<b>错误:</b> [$errno] $errstr<br />";
echo "错误记录已经发送完毕";
error_log(" 错 误:[$errno] $errstr", 1, "someone@example.com", "From:webmastere@example.com");
}
// 设置错误处理函数
set_error_handler("customError", E_USER_WARNING);
// trigger_error函数
$test = 5;
if ($test > 4) {
trigger_error("Value must be 4 or below", E_USER_WARNING);
}
?>
程序输出结果:
同时,在指定的someone@example.com邮箱中也将收到同样的信息。
异常处理
异常和错误不同,异常(Exception)用于在指定的错误发生时改变脚本的正常流程。用户可以捕获异常并做出相应处理。
异常类
PHP提供了一个异常类Exception,是所有异常类的基类。
Exception {
/* 属性 */
protected string $message;
protected int $code;
protected string $file;
protected int $line;
/* 方法 */
public __construct([string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]])
final public getMessage( void ): string
final public getPrevious( void ): Throwable
final public getCode( void ): int
final public getFile( void ): string
final public getLine( void ): int
final public getTrace( void ): array
final public getTraceAsString( void ): string
public __toString( void ): string
final private __clone( void ): void
}
关于该类中属性和方法的说明如下:
属性:
- message:异常消息内容
- code:异常代码
- file:抛出异常的文件名
- 抛出异常在该文件中的行号
方法:
Exeption::__construct
:异常构造函数Exeption::getMessage
:获取异常消息内容Exeption::getPrevious
:返回异常链中的前一个异常Exeption::getCode
:获取异常代码Exeption::getFile
:创建异常时的程序文件名称Exeption::getLine
:获取创建的异常所在文件中的行号Exeption::getTrace
:获取异常追踪信息Exeption::getTraceAsString
:获取字符串类型的异常追踪信息Exeption::__toString
:将异常对象转换为字符串Exeption::clone
:异常克隆
【示例】
<?php
// 设置错误级别为0,不报错
error_reporting(0);
function theDatabaseObj() {
$mysql = mysqli_connect('127.0.0.1', 'test', 'test', '3306');
if($mysql) {
return $mysql;
} else {
throw new Exception("Could not connect to the database");
}
}
function db() {
try {
$db = theDatabaseObj();
var_dump($db);
} catch (Exception $e) {
echo $e -> getMessage();
}
}
db();
?>
程序输出结果:
Could not connect to the database
异常的基本处理方法
当异常被触发时,通常会发生以下动作:
- 当前代码状态被保存
- 代码执行被切换到预定义的异常处理器函数。
- 根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行,或从代码中另外的位置继续执行。
当异常被抛出时,PHP会尝试查找匹配的catch代码块。如果异常没有捕获,而且又没有使用set_exception_handler()
做相应的处理,就将发生一个严重的错误,并且输出Uncaught Exception
(未捕获异常)的错误消息。
处理异常的程序通常应当包含如下几部分:
- try代码块:可能抛出异常的代码应该位于try代码块内。若没有触发异常,则代码将照常继续执行。
- throw代码块:这里定义如何触发异常。每一个throw必须对应至少一个catch。
- catch代码块:catch代码块会捕获异常,并创建一个包含异常信息的对象。
自定义的异常处理器
在PHP里遇到任何错误都会抛出一个错误,很少会主动抛出异常。PHP的异常处理机制并不完善,在PHP中先处理不可预料的异常是办不到的,我们必须事先定义一些异常,将各种可能出现的异常进行if…else判断,手动抛出异常。自定义异常类的方式如下:
<?php
// 首先自定义异常类,继承Exception
class MyException extends Exception {
public function errorMessage() {
// 错误消息
$errorMsg = '异常发生的行:'. $this->getLine() . ' in ' . $this->getFile() . ':<b>' . $this->getMessage(). '</b>不是一个有效的邮箱地址';
return $errorMsg;
}
}
// 在实际的业务代码中抛出自定义异常
$email = "someone@example.321com";
// 将可能抛出异常的代码放入try中
try {
// 检查是否符合条件
if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
// 如果邮件地址无效,则抛出异常
throw new MyException($email);
}
} catch (MyException $e) {
// 显示自定义的消息
echo $e->errorMessage();
}
?>
程序输出结果:
处理多个异常
可以使用多个if…else代码块,或switch代码块,或者嵌套多个异常,使用不同的异常类,并返回不同的错误消息。
【示例】
<?php
// 首先自定义异常类,继承Exception
class MyException extends Exception {
public function errorMessage() {
// 错误消息
$errorMsg = '异常发生的行:'. $this->getLine() . ' in ' . $this->getFile() . ':<b>' . $this->getMessage(). '</b>不是一个有效的邮箱地址';
return $errorMsg;
}
}
// 在实际的业务代码中抛出自定义异常
$email = "someone@yahoo.com";
// 将可能抛出异常的代码放入try中
try {
// 检查是否符合条件
if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
// 如果邮件地址无效,则抛出异常
throw new MyException($email);
}
// 检查邮箱是否是雅虎邮箱
if (strpos($email, "yahoo") !== FALSE) {
throw new Exception("$email 是一个雅虎邮箱");
}
} catch (MyException $e) {
// 显示自定义的消息
echo $e->errorMessage();
} catch (Exception $e) {
echo $e->getMessage();
}
?>
程序输出结果:
someone@yahoo.com 是一个雅虎邮箱
设置顶层异常处理器
所有未捕获的异常都可以通过顶层异常处理器来处理。顶层异常处理器使用set_exception_handler()
函数实现。
该函数用于创建运行期间用户自己的异常处理方法。该函数会返回旧的异常处理程序,若失败,则返回null。该函数的语法格式如下:
set_exception_handler(callable $exception_handler):callable
设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler
调用后异常会中止。
参数:
- exception_handler:当一个未捕获的异常发生时所调用的函数的名称。该处理函数需要接受一个参数,该参数是一个抛出的异常对象。
【示例】
<?php
// 定义顶层的异常处理程序
function myException($exception) {
echo "<b>异常是:</b>", $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('正在处理未捕获的异常'); // 抛出异常信息
?>
程序输出结果:
PHP7中的错误处理
PHP7改变了大多数错误的报告方式。不同于传统(PHP5)的错误报告机制,现在大多数错误都被作为Error异常自动抛出,而不必将错误看作异常抛出。
这种Error异常可以像Exception异常一样被第一个匹配的try/catch块捕获。Error类并非继承自Excepiton类,所以不能用catch(Exception $e)
来捕获Error,而是用catch(Error $e)
来捕获。
如下代码自动捕获了一个致命错误:
try{
$a = new cat();
}catch(Error $e){
echo 'error msg:' . $e->getMessage() .' error line:' . $e->getLine();
}
以上这种形式的错误处理只能在PHP7中可用。