在日常的PHP开发中,我们经常会遇到各种各样的PHP错误,有常见的语法错误,数据库错误,也有各种很难调试的奇怪问题。
一、PHP错误等级
在PHP中预定义了一些PHP错误常量,在Core.php
文件中可以查看定义。这里是一份完整的列表:Predefined Constants
这些变量不仅可以在PHP文件中使用,也可以用在php.ini
配置文件中。譬如在PHP中打开错误提示,可以使用下面的代码:
ini_set('display_errors','on');
error_reporting(E_ALL & ~E_NOTICE);
这两句PHP代码对应的php.ini
配置是:
display_errors = On
error_reporting = E_ALL & ~E_NOTICE
一般在生产环境不应该将错误信息打开,这样容易暴露服务器上的一些敏感信息,如网站路径,php文件函数,数据库连接等等。可以参考CodeIgniter的做法,在CI的入口文件index.php
中有这样的错误处理代码:
/*
*---------------------------------------------------------------
* ERROR REPORTING
*---------------------------------------------------------------
*
* Different environments will require different levels of error reporting.
* By default development will show errors but testing and live will hide them.
*/
if (defined('ENVIRONMENT'))
{
switch (ENVIRONMENT)
{
case 'development':
error_reporting(E_ALL);
break;
case 'testing':
case 'production':
error_reporting(0);
break;
default:
exit('The application environment is not set correctly.');
}
}
在开发环境,需要打开错误提示,可以在这段代码的上面 define('ENVIRONMENT', 'development')
,或者测试和生产环境定义testing
和production
就可以了。
二、PHP异常处理
PHP也和其他编程语言一样,支持异常的处理,基本的语法如下:
try
{
//可能出现错误或异常的代码
}
catch(Exception $e)
{
//对异常进行处理
die( 'Exception: ' .$e->getMessage() );
}
当一个异常被抛出时,其后的代码将不会继续执行,PHP 会尝试查找匹配的 catch
代码块。如果一个异常没有被捕获,而且又没用使用set_exception_handler()
作相应的处理的话,那么 PHP 将会产生一个严重的错误,并且输出未能捕获异常 "Uncaught Exception ..." 的提示信息。
三、顶层异常处理器 (Top Level Exception Handler)
使用set_error_handler
可以自定义PHP的错误处理函数。下面是一个简单的例子:
<?php
//error handler function
function customError($errno, $errstr, $errfile, $errline)
{
echo "<b>Custom error:</b> [$errno] $errstr<br />";
echo " Error on line $errline in $errfile<br />";
die();
}
//set error handler
set_error_handler("customError");
//trigger error
trigger_error("A custom error has been triggered");
?>
要注意的是,set_error_handler
例程只能处理用户级错误,如变量未定义或通过trigger_error
引发的错误等。如果需要处理其他错误譬如E_ERROR
, E_PARSE
, E_CORE_ERROR
,一种解决方法是使用register_shutdown_function
函数,这个函数可以让用户自定义PHP程序执行完成后执行的函数。如果PHP程序是出现错误导致的退出,可以通过error_get_last
函数获取最后一次发生的错误。在CodeIgniter.php
文件中可以看到使用set_error_handler
自定义了错误提示信息,当CodeIgniter出错时页面上可以看到自定义的显示,该代码位于Common.php
中的_exception_handler
和Exceptions.php
中的show_php_error
。我们修改CodeIgniter的代码,让其支持register_shutdown_function
。
首先在CodeIgniter.php
中添加如下代码:
set_error_handler('_exception_handler');
register_shutdown_function('_shutdown_handler');
然后在Common.php
中添加_shutdown_handler
:
/**
* Shutdown Handler
*
* The following error types cannot be handled with a user defined function:
* E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING,
* and most of E_STRICT raised in the file where set_error_handler() is called.
* So, we use shutdown function to work around this situation.
*
* @access private
* @return void
*/
if ( ! function_exists('_shutdown_handler'))
{
function _shutdown_handler()
{
$lasterror = error_get_last();
switch ($lasterror['type'])
{
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
case E_PARSE:
$severity = $lasterror['type'];
$message = $lasterror['message'];
$filepath = $lasterror['file'];
$line = $lasterror['line'];
//header('Location: /ci/index.php/error');
}
$_error =& load_class('Exceptions', 'core');
// Should we display the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
if (($severity & error_reporting()) == $severity)
{
$_error->show_php_error($severity, $message, $filepath, $line);
}
// Should we log the error? No? We're done...
if (config_item('log_threshold') == 0)
{
return;
}
$_error->log_exception();
}
}
注意:shutdown_handler
可以捕获到E_PARSE
,但是只能捕获到include的PHP文件里的语法错误。
四、PHP错误实例
熟悉常见的错误代码和返回信息可以快速诊断出代码中出现的问题。下面列出一些常见的PHP错误,及提示信息。
1. E_ERROR = 1
$b = undefined_func(); // 函数未定义 Fatal error: Call to undefined function func()
$a = new C(); // 类未定义 Fatal error: Class 'C' not found in
$a->undefined_func(); // 类的成员函数未定义 Fatal error: Call to undefined method C::undefined_func()
$a = 0;
for (;;) { // 死循环 Fatal error: Maximum execution time of 300 seconds exceeded
$a ++;
}
2. E_WARNING = 2
$a = 1;
$b = 0;
$c = $a / $b; // 被零除 Warning: Division by zero
3. E_PARSE = 4
$b = 1 // 语法错误,少个逗号 Parse error: syntax error, unexpected $end
if (true)
{
if (true)
{
if (false)
{ // 语法错误,缺右括号
}
}
4. E_NOTICE = 8
$b = $undefined_var; // 变量未定义 Notice:Undefined variable: undefined_var
5. E_USER_ERROR/E_USER_WARNING/E_USER_NOTICE
trigger_error("This is an error.", E_USER_ERROR); // User error
参考
- PHP异常处理详解
- PHP Error Handling
- PHP set_error_handler() 函数
- register_shutdown_function
- register_shutdown_function 函数详解