如何在PHP中获得有用的错误消息?

时间:2009-05-10 09:48:13

标签: php debugging error-handling

我发现PHP中的编程非常令人沮丧。我经常尝试运行脚本,然后再回一个空白屏幕。没有错误消息,只是空屏幕。原因可能是一个简单的语法错误(错误的括号,缺少分号),或者函数调用失败,或其他完全错误。

很难弄清楚出了什么问题。我最终评论出代码,在任何地方输入“echo”语句等等,试图缩小问题范围。但肯定有一个更好的方法,对吗?

那么,有没有办法让PHP产生像Java那样有用的错误信息呢? 任何人都可以推荐好的PHP调试技巧和技巧吗?

29 个答案:

答案 0 :(得分:470)

对于语法错误,您需要在php.ini中启用错误显示。默认情况下,这些是关闭的,因为您不希望“客户”看到错误消息。有关2指令的信息,请参阅PHP文档中的Check this pageerror_reportingdisplay_errorsdisplay_errors可能是您想要更改的人。如果你不能修改php.ini,你也可以将以下行添加到.htaccess文件中:

php_flag  display_errors        on
php_value error_reporting       2039

您可能需要考虑使用E_ALL的值(如Gumbo所述)为您的error_reporting版本的PHP获取所有错误。 more info

3个其他项目:(1)您可以检查错误日志文件,因为它将包含所有错误(除非已禁用日志记录)。 (2)添加以下2行将帮助您调试非语法错误的错误:

error_reporting(-1);
ini_set('display_errors', 'On');

(3)另一种选择是使用编辑器在您键入时检查错误,例如PhpEd。 PhpEd还带有一个调试器,可以提供更详细的信息。 (PhpEd调试器与xdebug非常相似,并直接集成到编辑器中,因此您可以使用1个程序来完成所有操作。)

卡特曼的link也非常好:http://www.ibm.com/developerworks/library/os-debug/

答案 1 :(得分:434)

以下内容可以解决所有错误:

ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
error_reporting(-1);

另见以下链接

答案 2 :(得分:54)

您可以在要调试的文件中包含以下行:

error_reporting(E_ALL);
ini_set('display_errors', '1');

这会覆盖php.ini中的默认设置,这只会让PHP将错误报告给日志。

答案 3 :(得分:51)

PHP配置

php.ini中的2个条目指示错误输出:

  1. display_errors
  2. error_reporting
  3. 制作中,display_errors通常设置为Off(这是一件好事,因为生产网站中的错误显示通常是不可取的!)。

    但是,在开发中,应将其设置为On,以便显示错误。 查看

    error_reporting(自PHP 5.3起)默认设置为E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED(意思是,除通知,严格标准和弃用声明外,所有内容均已显示)。如有疑问,请将其设置为E_ALL以显示所有错误。 查看

    <哇>哇哇!不检查!我不能改变我的php.ini!

    这太遗憾了。通常共享主机不允许更改其php.ini文件,因此,该选项很遗憾。但不要害怕!我们有other options

    运行时配置

    在所需的脚本中,我们可以在运行时更改php.ini条目!意思是,它会在脚本运行时运行!甜!

    error_reporting(E_ALL);
    ini_set("display_errors", "On");

    这两行与改变上面的php.ini条目效果相同!真棒!

    我仍然得到一个空白页/ 500错误!

    这意味着脚本甚至没有运行!当您遇到语法错误时,通常会发生这种情况!

    由于语法错误,脚本甚至无法进入运行时。它在编译时失败,这意味着它将使用php.ini中的值,如果您没有更改,则可能不允许显示错误。

    错误日志

    此外,PHP默认记录错误。在共享主机中,它可能位于专用文件夹中,也可能位于与违规脚本相同的文件夹中。

    如果您有权访问php.ini,可以在 error_log 条目下找到它。

答案 4 :(得分:29)

有一个名为“xdebug”的真正有用的扩展程序,可以使您的报告更加出色。

答案 5 :(得分:24)

对于快速的动手故障排除我通常建议在SO:

error_reporting(~0); ini_set('display_errors', 1);

放在故障排除脚本的开头。这并不完美,完美的变体是你在php.ini中启用它并且你在PHP中记录错误以捕获语法和启动错误。

此处列出的设置显示所有错误,通知和警告,包括严格的错误,无论哪个PHP版本。

接下来要考虑的事项:

  • 安装Xdebug并使用IDE启用远程调试。

参见:

答案 6 :(得分:16)

如果你非常酷,你可以试试:

$test_server = $_SERVER['SERVER_NAME'] == "127.0.0.1" || $_SERVER['SERVER_NAME'] == "localhost" || substr($_SERVER['SERVER_NAME'],0,3) == "192";

ini_set('display_errors',$test_server);
error_reporting(E_ALL|E_STRICT);

这只会在您本地运行时显示错误。它还为您提供了test_server变量,以便在适当的其他地方使用。

在脚本运行之前发生的任何错误都不会被捕获,但是对于我所犯的99%的错误,这不是问题。

答案 7 :(得分:15)

要坚持这个并使其成为confortale,您可以编辑您的php.ini文件。它通常存储在/etc/php.ini/etc/php/php.ini中,但更多本地php.ini可能会覆盖它,具体取决于您的托管服务商的设置指南。在顶部检查phpinfo()Loaded Configuration File文件,以确定哪个文件最后加载。

在该文件中搜索display_errors。应该只有3个实例,其中2个被评论。

将未注释的行更改为:

display_errors = stdout

答案 8 :(得分:15)

在页面顶部选择一个参数

error_reporting(E_ERROR | E_WARNING | E_PARSE);

答案 9 :(得分:13)

我建议Nette Tracy更好地可视化PHP中的错误和异常:

Nette Tracy screenshot

答案 10 :(得分:12)

error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
ini_set('html_errors', 1);

此外,您可以使用xdebug获取更详细的信息。

答案 11 :(得分:11)

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

答案 12 :(得分:9)

error_reporting(E_ALL | E_STRICT);

启用php.ini中的显示错误

答案 13 :(得分:8)

您可以在PHP中注册自己的error handler。例如,将所有错误转储到文件可能会帮助您处理这些模糊的情况。请注意,无论您当前设置的error_reporting是什么,都会调用您的函数。非常基本的例子:

function dump_error_to_file($errno, $errstr) {
    file_put_contents('/tmp/php-errors', date('Y-m-d H:i:s - ') . $errstr, FILE_APPEND);
}
set_error_handler('dump_error_to_file');

答案 14 :(得分:6)

从PHP中获取有用错误所需的两个关键行是:

ini_set('display_errors',1);
 error_reporting(E_ALL);

正如其他贡献者所指出的那样,出于安全原因,这些默认情况下会被关闭。作为一个有用的提示 - 当您设置网站时,为您的不同环境进行切换非常方便,以便在本地和开发环境中默认启用这些错误。这可以通过以下代码实现(理想情况下,在index.php或配置文件中,因此从一开始就是活动的):

switch($_SERVER['SERVER_NAME'])
{
    // local
    case 'yourdomain.dev':
    // dev
    case 'dev.yourdomain.com':
        ini_set('display_errors',1);
        error_reporting(E_ALL);
    break;
    //live
    case 'yourdomain.com':
        //...
    break;
}

答案 15 :(得分:6)

您可能还想尝试使用PHPStorm作为代码编辑器。当您在编辑器中输入时,它会发现许多PHP和其他语法错误。

答案 16 :(得分:5)

FirePHP也很有用。

答案 17 :(得分:5)

如果您是ubuntu用户,请转到您的终端并运行此命令

sudo tail -50f /var/log/apache2/error.log

它将显示最近50个错误。 apache2有一个错误文件error.log,它记录了所有错误。

答案 18 :(得分:3)

除了error_reporting和display_errors ini设置之外,您还可以从Web服务器的日志文件中获取SYNTAX错误。当我开发PHP时,我将开发系统的Web服务器日志加载到我的编辑器中。每当我测试一个页面并得到一个空白屏幕时,日志文件就会过时,我的编辑会询问我是否要重新加载它。当我这样做时,我跳到底部,语法错误。例如:

[Sun Apr 19 19:09:11 2009] [error] [client 127.0.0.1] PHP Parse error:  syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING in D:\\webroot\\test\\test.php on line 9

答案 19 :(得分:3)

“错误”是开发人员了解错误并解决问题以使系统完美运行的最有用的东西。

PHP提供了一些更好的方法来了解开发人员为什么以及他们的代码在哪里获得错误,因此通过了解这些错误,开发人员可以在许多方面使代码更好。

在脚本顶部写下以下两行以获取所有错误消息的最佳方法:

error_reporting(E_ALL);
ini_set("display_errors", 1);

在IDE中使用xdebug等调试工具的另一种方法。

答案 20 :(得分:3)

要启用完整错误报告,请将其添加到您的脚本中:

error_reporting(E_ALL);

这会导致出现最小的警告。而且,以防万一:

ini_set('display_errors', '1');

将强制显示错误。这应该在生产服务器中关闭,但不是在开发时关闭。

答案 21 :(得分:3)

您可以启用完整错误报告(包括通知和严格消息)。有些人觉得这个太冗长了,但值得一试。在php.ini中将error_reporting设置为E_ALL | E_STRICT

error_reporting = E_ALL | E_STRICT

E_STRICT会通知您有关已弃用的功能,并为您提供有关执行某些任务的最佳方法的建议。

如果您不想发布通知,但发现其他消息类型有用,请尝试排除通知:

error_reporting = (E_ALL | E_STRICT) & ~E_NOTICE

还要确保在php.ini中启用了display_errors。如果您的PHP版本早于5.2.4,请将其设置为On

display_errors = "On"

如果您的版本是5.2.4或更高版本,请使用:

display_errors = "stderr"

答案 22 :(得分:1)

除了这里所有精彩的答案之外,我还要特别提及MySQLi和PDO库。

为了...

  1. 始终查看与数据库相关的错误,并且
  2. 避免检查方法的返回类型以查看是否出了问题

最好的选择是将库配置为throw exceptions

MySQLi

将此添加到脚本顶部附近

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

在使用new mysqli()mysqli_connect()之前最好放置此位置。

PDO

在您的连接实例上将PDO::ATTR_ERRMODE属性设置为PDO::ERRMODE_EXCEPTION。您可以在构造函数中执行此操作

$pdo = new PDO('driver:host=localhost;...', 'username', 'password', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

或创建后

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

答案 23 :(得分:1)

  

此答案是由冗余部门的部门提供给您的。

  1. ini_set() / php.ini / .htaccess / .user.ini

    设置display_errorserror_reporting现已被充分介绍。但是只是回顾一下何时使用哪个选项:

    • ini_set()error_reporting()仅适用于运行时错误。
    • php.ini应该主要针对开发设置进行编辑。 (Web服务器和CLI版本通常具有不同的php.ini)。
    • .htaccess标志仅适用于过时的设置(查找新的托管服务商!管理良好的服务器更便宜。)
    • .user.ini是用于现代设置(FCGI / FPM)的部分php.ini。

    作为运行时错误的粗略替代方案,您通常可以使用:

    set_error_handler("var_dump");   // ignores error_reporting and `@` suppression
    
  2. error_get_last()

    在禁用error_display的情况下,可用于检索上次运行时通知/警告/错误。

  3. $php_errormsg

    是一个超局部变量,还包含最后一个PHP运行时消息。

  4. isset()消失了!

    我知道这会使很多人不满意,但是{strong>不不应该由新手使用issetempty。您可以在验证代码正常后的 之后添加通知抑制。但是从来没有。

    我们最近遇到的许多“无法正常工作”的问题都是由于错字造成的:

    if(isset($_POST['sumbit']))
    #                  ↑↑
    

    如果您的代码中充斥着isset / empty / array_keys_exists,您将不会得到任何有用的通知。有时更多sensible to use @,因此通知和警告至少会记录在日志中。

  5. assert_options(ASSERT_ACTIVE|ASSERT_WARNING);

    获取assert()部分的警告。 (这很不常见,但是更精通的代码可能包含一些代码。)

    PHP7在php.ini中也需要zend.assertions=1

  6. declare(strict_types=1);

    将PHP转换为严格类型的语言并不能解决很多逻辑错误,但绝对是调试的一种选择。

  7. PDO / MySQLi

    @Phil已经提到了PDO/MySQLi error reporting选项。当然,其他数据库API也有类似的选项。

  8. json_last_error() + json_last_error_msg

    用于JSON解析。

  9. preg_last_error()

    用于regexen。

  10. CURLOPT_VERBOSE

    要调试curl请求,至少需要CURLOPT_VERBOSE。

  11. shell/exec()

    同样,shell命令执行不会单独产生错误。您总是需要2>&1并查看$ errno。

答案 24 :(得分:0)

将此代码放入您的代码中。

error_reporting(-1);
ini_set('display_errors', 'On');

答案 25 :(得分:0)

我像这样解决了整个 500 问题:

A.检查php.ini参数

  1. php.ini >> error_reporting = E_ALL | E_STRICT
  2. php.ini >> display_errors = On
  3. php.ini >> display_startup_errors = 关闭

B.更新 IIS 管理器参数

  1. IIS 管理器 >> 错误页面 >> 500 >> 编辑功能设置 >> 详细错误

在这一步中,您会遇到 500 个这样的错误,并且没有加载 html。

enter image description here

  1. IIS 管理器 >> FastCGI 设置 >> php-cgi.exe >> 标准错误模式 >> IgnoreAndReurn200

在这一步中,您可以看到包含这样的 php 错误的 html 页面。 enter image description here

完成:)

答案 26 :(得分:0)

PHP错误处理

有时您的应用程序将无法正常运行,从而导致错误。有多种可能导致错误的原因,例如:

Web服务器可能磁盘空间不足 用户可能在表单字段中输入了无效的值 您尝试访问的文件或数据库记录可能不存在 该应用程序可能无权写入磁盘上的文件 应用程序需要访问的服务可能暂时不可用 这些类型的错误称为运行时错误,因为它们在脚本运行时发生。它们不同于在脚本运行之前需要修复的语法错误。

专业的应用程序必须具有适当处理此类运行时错误的功能。通常,这意味着更清楚,准确地将问题告知用户。

了解错误级别

通常,当出现问题导致脚本无法正常运行时,PHP引擎将触发错误。每个错误都由一个整数值和一个关联的常数表示。下表列出了一些常见的错误级别:

enter image description here

每当PHP脚本遇到问题时,PHP引擎都会触发一个错误,但是您也可以自己触发错误以生成更多用户友好的错误消息。这样,您可以使应用程序更加复杂。以下部分描述了一些用于处理PHP错误的常用方法:

  

使用die()函数进行基本错误处理

<?php // Try to open a non-existent file
     $file = fopen("sample.txt", "r");
?>

如果文件不存在,您可能会收到如下错误: 警告:fopen(sample.txt)[function.fopen]:无法打开流:第2行的C:\ wamp \ www \ project \ test.php中没有此类文件或目录

如果我们遵循一些简单的步骤,我们可以防止用户收到这样的错误消息:

<?php
if(file_exists("sample.txt")){
    $file = fopen("sample.txt", "r");
} else{
    die("Error: The file you are trying to access doesn't exist.");
}
?>

现在,如果您运行上述脚本,您将收到如下错误消息:错误:您尝试访问的文件不存在。

您可以通过在访问文件之前进行一次简单的检查来了解文件是否存在,我们可以生成一条对用户更有意义的错误消息。

上面使用的die()函数只是显示自定义错误消息,如果找不到“ sample.txt”文件,则终止当前脚本。

  

创建自定义错误处理程序

您可以创建自己的错误处理函数,以处理PHP引擎生成的运行时错误。自定义错误处理程序为您提供了更大的灵活性,并且可以更好地控制错误,它可以检查错误并决定如何处理错误,它可以向用户显示一条消息,将错误记录在文件或数据库中,或者通过e发送-mail,尝试解决问题并继续,退出脚本执行或完全忽略该错误。

自定义错误处理函数必须能够处理至少两个参数(errno和errstr),但是可以选择接受其他三个参数(errfile,errline和errcontext),如下所述:

enter image description here

这是一个简单的自定义错误处理功能的示例。每当发生错误时,无论多么琐碎,都会触发此处理程序customError()。然后将错误的详细信息输出到浏览器,并停止执行脚本。

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
?>

您需要告诉PHP使用您的自定义错误处理函数-只需调用内置的set_error_handler()函数,并传入函数名称即可。

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}

// Set error handler
set_error_handler("customError");

// Trigger error
echo($test);
?>
  

错误记录

在文本文件中记录错误消息

您还可以将错误的详细信息记录到日志文件中,如下所示:

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("calcDivision(): The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
function customError($errno, $errstr, $errfile, $errline, $errcontext){
    $message = date("Y-m-d H:i:s - ");
    $message .= "Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, ";
    $message .= "Variables:" . print_r($errcontext, true) . "\r\n";

    error_log($message, 3, "logs/app_errors.log");
    die("There was a problem, please try again.");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "This will never be printed.";
?>
  

触发错误

尽管PHP引擎在遇到脚本问题时会触发错误,但是您也可以自己触发错误。这可以帮助使您的应用程序更强大,因为它可以在潜在问题变成严重错误之前对其进行标记。

要从脚本内部触发错误,请调用trigger_error()函数,并传入要生成的错误消息:

trigger_error("There was a problem.");

考虑以下计算两个数字除法的函数。

<?php
function calcDivision($dividend, $divisor){
    return($dividend / $divisor);
}

// Calling the function
echo calcDivision(10, 0);
?>

如果将零(0)值作为$ divisor参数传递,则PHP引擎生成的错误将类似于以下内容:警告:在C:\ wamp \ www \ project \中被零除第3行的test.php

该消息看起来内容不多。考虑下面的示例,该示例使用trigger_error()函数生成错误。

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}

// Calling the function
echo calcDivision(10, 0);
?>

现在脚本生成此错误消息:警告:在第4行的C:\ wamp \ www \ project \ error.php中,除数不能为零

如您所见,第二个示例生成的错误消息与上一个示例相比更清楚地说明了问题。

答案 27 :(得分:0)

除了上面的许多优秀答案,您还可以在项目中实现以下两个功能。它们将在应用程序/脚本退出之前捕获每个非语法错误。 在功能内部,您可以进行回溯并记录或呈现令人愉快的“网站正在维护”消息给公众。

致命错误:

register_shutdown_function

http://php.net/manual/en/function.register-shutdown-function.php

错误:

set_error_handler

http://php.net/manual/en/function.set-error-handler.php

回溯:

debug_backtrace

http://php.net/manual/en/function.debug-backtrace.php

答案 28 :(得分:0)

启用错误报告是正确的解决方案,但它似乎不会在打开它的程序中生效,而只会在随后包含的程序中生效。

因此,我总是创建一个文件/程序(我通常称之为“genwrap.php”),它与此处的流行解决方案具有基本相同的代码(即打开错误报告),然后它还包括页面I实际上想打电话。

实现此调试有两个步骤;

一个 - 创建genwrap.php并将此代码放入其中:

<?php
error_reporting(-1);
ini_set('display_errors', 'On');

include($_REQUEST['page']);
?>

两个 - 通过genwrap.php更改指向您要调试的程序/页面的链接,

例如:改变:

$.ajax('dir/pgm.php?param=val').done(function(data) { /* ... */

$.ajax('dir/genwrap.php?page=pgm.php&param=val').done(function(data) { /* ... */