在 PHP 中,默认的错误处理很简单。一条错误消息会被发送到浏览器,这条消息带有文件名、行号以及描述错误的消息。
PHP 错误处理
在创建脚本和 Web 应用程序时,错误处理是一个重要的部分。如果您的代码缺少错误检测编码,那么程序看上去很不专业,也为安全风险敞开了大门。
本教程介绍了 PHP 中一些最为重要的错误检测方法。
我们将为您讲解不同的错误处理方法:
· 简单的 "die()" 语句
· 自定义错误和错误触发器
· 错误报告
基本的错误处理:使用 die() 函数
第一个实例展示了一个打开文本文件的简单脚本:
<?php $open=fopen('error.txt','r'); echo $open; ?>
如果文件不存在,您会得到以下类似这样的错误:
Warning: fopen(error.txt) [function.fopen]: failed to open stream:
No such file or directory in /www/php/test/test.php on line 2
为了避免用户得到类似上面的错误消息,我们在访问文件之前检测该文件是否存在:
<?php header("Content-type:text/html;charset=utf-8"); if(!file_exists('error.txt')){ die("文件不存在"); }else{ $file=fopen('error.txt','r'); } ?>
现在,如果文件不存在,您会得到类似这样的错误消息:
文件不存在
相比之前的代码,上面的代码更有效,这是由于它采用了一个简单的错误处理机制在错误之后终止了脚本。
然而,简单地终止脚本并不总是恰当的方式。让我们研究一下用于处理错误的备选的 PHP 函数。
创建自定义错误处理器
创建一个自定义的错误处理器非常简单。我们很简单地创建了一个专用函数,可以在 PHP 中发生错误时调用该函数。
该函数必须有能力处理至少两个参数 (error level 和 error message),但是可以接受最多五个参数(可选的:file, line-number 和 error context):
error_function (error_level,error_message,error_file,error_line,error_context)
参数 | 描述 |
error_level | 必需。为用户定义的错误规定错误报告级别。必须是一个数字。参见下面的表格:错误报告级别。 |
error_message | 必需。为用户定义的错误规定错误消息。 |
error_file | 可选。规定错误发生的文件名。 |
error_line | 可选。规定错误发生的行号。 |
error_context | 可选。规定一个数组,包含了当错误发生时在用的每个变量以及它们的值。 |
错误报告级别
这些错误报告级别是用户自定义的错误处理程序处理的不同类型的错误:
值 | 常量 | 描述 |
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,但可被用户定义的处理程序捕获。(参见 set_error_handler()) |
8191 | E_ALL | 所有错误和警告。(在 PHP 5.4 中,E_STRICT 成为 E_ALL 的一部分) |
现在,让我们创建一个处理错误的函数:
<?php header("Content-type:text/html;charset=utf-8"); function customError($errno, $errstr) { echo "<b>Error:</b> [$errno] $errstr<br>"; echo "脚本结束"; die(); } ?>
上面的代码是一个简单的错误处理函数。当它被触发时,它会取得错误级别和错误消息。然后它会输出错误级别和消息,并终止脚本。
现在,我们已经创建了一个错误处理函数,我们需要确定在何时触发该函数。
设置错误处理程序
PHP 的默认错误处理程序是内建的错误处理程序。我们打算把上面的函数改造为脚本运行期间的默认错误处理程序。
可以修改错误处理程序,使其仅应用到某些错误,这样脚本就能以不同的方式来处理不同的错误。然而,在本例中,我们打算针对所有错误来使用我们自定义的错误处理程序:
set_error_handler("customError");
由于我们希望我们的自定义函数能处理所有错误,set_error_handler() 仅需要一个参数,可以添加第二个参数来规定错误级别
实例
我们结合上面所学的知识,尝试输出不存在的变量,来测试这个错误处理程序:
<?php header("Content-type:text/html;charset=utf-8"); // 错误处理函数 function customError($errno, $errstr) { echo "<b>Error:</b> [$errno] $errstr"; } // 设置错误处理函数 set_error_handler("customError"); // 触发错误 echo($test); //关闭了所有的错误显示 error_reporting(0); //显示所有错误 //error_reporting(E_ALL); //显示所有错误,但不显示提示 //error_reporting(E_ALL & ~ E_NOTICE); ?>
程序运行结果:
Error: [8] Undefined variable: test
运行结果告诉我们 错误级别为8 ,错误信息是:不存在的变量
触发错误
在脚本中用户输入数据的位置,当用户的输入无效时触发错误是很有用的。在 PHP 中,这个任务由 trigger_error() 函数完成。
实例
在本例中,如果 "test" 变量大于 "1",就会发生错误:
<?php header("Content-type:text/html;charset=utf-8"); $test=2; if ($test>1) { trigger_error("变量值必须小于等于 1"); } ?>
程序运行结果:
Notice: 变量值必须小于等于 1 in D:\WWW\Advanced tutorial\error\error_1.php on line 6
您可以在脚本中任何位置触发错误,通过添加的第二个参数,您能够规定所触发的错误级别。
可能的错误类型:
· E_USER_ERROR - 致命的用户生成的 run-time 错误。错误无法恢复。脚本执行被中断。
· E_USER_WARNING - 非致命的用户生成的 run-time 警告。脚本执行不被中断。
· E_USER_NOTICE - 默认。用户生成的 run-time 通知。在脚本发现可能有错误时发生,但也可能在脚本正常运行时发生。
实例
在本例中,如果 "test" 变量大于 "1",则发生 E_USER_WARNING 错误。如果发生了 E_USER_WARNING,我们将使用我们自定义的错误处理程序并结束脚本:
<?php header("Content-type:text/html;charset=utf-8"); // 错误处理函数 function customError($errno, $errstr) { echo "<b>Error:</b> [$errno] $errstr<br>"; echo "脚本结束"; die(); } // 设置错误处理函数 set_error_handler("customError",E_USER_WARNING); // 触发错误 $test=2; if ($test>1) { trigger_error("变量值必须小于等于 1",E_USER_WARNING); } ?>
程序运行结果:
Error: [512] 变量值必须小于等于 1
脚本结束
运行结果告诉我们 错误级别的值为512 错误信息变成了我们用trigger_error函数所设置的的提示信息
错误日志记录
在一些公司里面,有专门的日志收集系统。日志收集系统会在背后默默的帮你收集错误、警告、提示。
也有些公司没有专门的日志收集系统,通过文件来服务器当中的运行日志。
其中:PHP的错误,警告这些是必须要收信的。
那么问题来了——不让用户看到,设置好错误报告级别好,如何将错误收集到日志系统中呢?
这里有需要使用到php.ini的相关配置项。这两个配置项为:
错误消息类型 | 说明 |
0 | 发送至默认的error_log指定位置 |
1 | 发送到指定的邮件位置 |
3 | 发送至指定的文件位置 |
举例
<?php //无法连接到数据库服务器,直接记录到php.ini 中的error_log指定位置 error_log("无法连接到数据库服务器服务器"); //可以发送邮件,但是php.ini必须配置过邮件系统 error_log('可以用邮件报告错误,让运维人员半夜起床干活',1 ,'liwenkai@phpxy.com'); //记录在指定的位置 error_log("我是一个错误哟", 3, "d:/test/my-errors.log"); ?>
实例
在下面的例子中,如果特定的错误发生,我们将发送带有错误消息的电子邮件,并结束脚本:
<?php //error handler function function customError($errno, $errstr) { echo "<b>Error:</b> [$errno] $errstr<br />"; echo "Webmaster has been notified"; error_log("Error: [$errno] $errstr",1, "someone@example.com","From: webmaster@example.com"); } //set error handler set_error_handler("customError",E_USER_WARNING); //trigger error $test=2; if ($test>1) { trigger_error("Value must be 1 or below",E_USER_WARNING); } ?>
程序运行结果:
Error: [512] Value must be 1 or below
Webmaster has been notified
接收自以上代码的邮件类似这样:
Error: [512] Value must be 1 or below
这个方法不适合所有的错误。常规错误应当通过使用默认的 PHP 记录系统在服务器上进行记录。
注意:error_log 中发送邮件可能对初学者不熟,您可以不用掌握些块知识。
error_reporting 报告错误类型
error_reporting 是指错误报告。在php.ini中也有这样一个参数。这个参数。决定了PHP引擎记录、报告、显示哪些错误类型。
一、 在php.ini中error_reporting参数。如若error_reporting参数设置为0。整个PHP引擎发错误均不会显示、输出、记录。在下一章将要讲到的日志记录中,也不会记录。
如果我们想显示所有错误可以写上:
error_reporting = E_ALL
想要显示所有错误但排除提示,可以将这个参数写为:
error_reporting = E_ALL & ~ E_NOTICE
显示所有错误,但排除提示、兼容性和未来兼容性。可写为:
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
二、在有些情况下我们无权限操作php.ini文件,又想要控制error_reporting怎么办呢?
在运行的xxxx.php文件中开始处,我们可以使用error_reporting()函数灰达到目标。
<?php //关闭了所有的错误显示 error_reporting(0); //显示所有错误 //error_reporting(E_ALL); //显示所有错误,但不显示提示 //error_reporting(E_ALL & ~ E_NOTICE); ?>
上面的代码你可以试试,故意写错代码看看。在当前文件中还会不会显示指定的错误。
[扩展、了解知识点]:
@ 符是我们之前学习过的单行不显示错误,请不用或者少用@符。
实例
我们拿读取一个不存在的文件,这样的php代码来演示实现过程:
<?php //读取一个不存在的adsaf.txt文件,用@符抑制错误 @$fp = fopen('adsaf.txt','r'); ?> @符效率较低,它在php内核中的实现过程是: <?php //关闭错误 error_reporting(0); //读取一个不存在的文件,显示错误 //显示错误 error_reporting(E_ALL & ~ E_NOTICE); ?>