如何让 PHP 在出现错误时生成回溯?

发布于 2024-07-28 18:57:27 字数 76 浏览 11 评论 0原文

尝试使用 PHP 的默认仅当前行错误消息来调试 PHP 是可怕的。

当产生错误时,如何让 PHP 产生回溯(堆栈跟踪)?

Trying to debug PHP using its default current-line-only error messages is horrible.

How can I get PHP to produce a backtrace (stack trace) when errors are produced?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

鹿港巷口少年归 2024-08-04 19:00:00

PHP Debugger 还可以进行类似于 PHP Error 的回溯,并具有更多选项。

如果您愿意,您可以使用 set_error_handlerdebug_backtrace 轻松制作自己的

set_error_handler ($error_handler, error_reporting);
/**
 * @var int $errno the error number
 * @var string $errstr the error message
 * @var string $errfile the error file
 * @var int $errline the line of the error
 */
$error_handler = function($errno, $errstr, $errfile, $errline){
    $trace = debug_backtrace();
    array_shift($backtrace);//remove the stack about this handler
    foreach($trace as $k => $v){
        //parse your backtrace
    }
}

另请注意,对于回溯中的内部堆栈,某些键将不会被设置。 如果出现所有错误,请务必在使用该密钥进行操作之前检查该密钥是否存在:)

PHP DeBugger also does a back trace similiar to PHP Error with more options.

If you want you can easily make your own with set_error_handler and debug_backtrace

set_error_handler ($error_handler, error_reporting);
/**
 * @var int $errno the error number
 * @var string $errstr the error message
 * @var string $errfile the error file
 * @var int $errline the line of the error
 */
$error_handler = function($errno, $errstr, $errfile, $errline){
    $trace = debug_backtrace();
    array_shift($backtrace);//remove the stack about this handler
    foreach($trace as $k => $v){
        //parse your backtrace
    }
}

Also note that for internal stacks in the backtrace some of the keys will not be set. Be sure to check if the key exist before you do something with it if you have all errors on :)

一个人的旅程 2024-08-04 18:59:48

您可以使用 (new \Exception())->getTraceAsString() 代替 debug_backtrace()

set_error_handler(function(int $severity, string $message, string $file, int $line) {
    if (!(error_reporting() & $severity)) {
        return false;
    }

    $severities = [
        E_ERROR => 'ERROR',
        E_WARNING => 'WARNING',
        E_PARSE => 'PARSE',
        E_NOTICE => 'NOTICE',
        E_CORE_ERROR => 'CORE_ERROR',
        E_CORE_WARNING => 'CORE_WARNING',
        E_COMPILE_ERROR => 'COMPILE_ERROR',
        E_COMPILE_WARNING => 'COMPILE_WARNING',
        E_USER_ERROR => 'USER_ERROR',
        E_USER_WARNING => 'USER_WARNING',
        E_USER_NOTICE => 'USER_NOTICE',
        E_STRICT => 'STRICT',
        E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
        E_DEPRECATED => 'DEPRECATED',
        E_USER_DEPRECATED => 'USER_DEPRECATED',
    ];

    $e = new \Exception;

    // Just remove the current point from the trace
    $reflection = new \ReflectionProperty(get_class($e), 'trace');
    $reflection->setAccessible(true);
    $trace = $reflection->getValue($e);
    array_shift($trace);
    $reflection->setValue($e, $trace);

    $text = '';
    $text .= ($severities[$severity] ?? $severity) . ': ';
    $text .= "$message in $file($line)\n";
    $text .= "Stack trace:\n";
    $text .= $e->getTraceAsString();

    error_log($text);

    if (in_array($severity, [
        E_CORE_ERROR,
        E_ERROR,
        E_RECOVERABLE_ERROR,
        E_PARSE,
        E_COMPILE_ERROR,
        E_USER_ERROR,
    ], true)) {
        http_response_code(500);
        exit(255);
    }

    return true;
});

输出:

[16-Feb-2022 00:01:09 UTC] DEPRECATED: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /home/user/project/doSomething.php(3)
Stack trace:
#0 /home/user/project/doSomething.php(3): trim(NULL)
#1 /home/user/project/index.php(4): doSomething()
#2 {main}

You can use (new \Exception())->getTraceAsString() instead of debug_backtrace():

set_error_handler(function(int $severity, string $message, string $file, int $line) {
    if (!(error_reporting() & $severity)) {
        return false;
    }

    $severities = [
        E_ERROR => 'ERROR',
        E_WARNING => 'WARNING',
        E_PARSE => 'PARSE',
        E_NOTICE => 'NOTICE',
        E_CORE_ERROR => 'CORE_ERROR',
        E_CORE_WARNING => 'CORE_WARNING',
        E_COMPILE_ERROR => 'COMPILE_ERROR',
        E_COMPILE_WARNING => 'COMPILE_WARNING',
        E_USER_ERROR => 'USER_ERROR',
        E_USER_WARNING => 'USER_WARNING',
        E_USER_NOTICE => 'USER_NOTICE',
        E_STRICT => 'STRICT',
        E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
        E_DEPRECATED => 'DEPRECATED',
        E_USER_DEPRECATED => 'USER_DEPRECATED',
    ];

    $e = new \Exception;

    // Just remove the current point from the trace
    $reflection = new \ReflectionProperty(get_class($e), 'trace');
    $reflection->setAccessible(true);
    $trace = $reflection->getValue($e);
    array_shift($trace);
    $reflection->setValue($e, $trace);

    $text = '';
    $text .= ($severities[$severity] ?? $severity) . ': ';
    $text .= "$message in $file($line)\n";
    $text .= "Stack trace:\n";
    $text .= $e->getTraceAsString();

    error_log($text);

    if (in_array($severity, [
        E_CORE_ERROR,
        E_ERROR,
        E_RECOVERABLE_ERROR,
        E_PARSE,
        E_COMPILE_ERROR,
        E_USER_ERROR,
    ], true)) {
        http_response_code(500);
        exit(255);
    }

    return true;
});

Output:

[16-Feb-2022 00:01:09 UTC] DEPRECATED: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /home/user/project/doSomething.php(3)
Stack trace:
#0 /home/user/project/doSomething.php(3): trim(NULL)
#1 /home/user/project/index.php(4): doSomething()
#2 {main}
终弃我 2024-08-04 18:59:34

如果您无法安装调试器,则使用此函数解决致命错误以获取“致命堆栈”。 检查下面的代码和示例,更好地解释如何使用它:

// Give an extra parameter to the filename
// to save multiple log files
function _fatalog_($extra = false)
{
    static $last_extra;

    // CHANGE THIS TO: A writeable filepath in your system...
    $filepath = '/var/www/html/sites/default/files/fatal-'.($extra === false ? $last_extra : $extra).'.log';

    if ($extra===false) {
        unlink($filepath);
    } else {
        // we write a log file with the debug info
        file_put_contents($filepath, json_encode(debug_backtrace()));
        // saving last extra parameter for future unlink... if possible...
        $last_extra = $extra;
    }
}

这是一个如何使用它的示例:

// A function which will produce a fatal error
function fatal_example()
{
    _fatalog_(time()); // writing the log
    $some_fatal_code = array()/3; // fatality!
    _fatalog_(); // if we get here then delete last file log
}

最后阅读日志的内容...

var_dump(json_decode(file_get_contents('/path/to-the-fatal.log')));

希望有帮助!

If you can't install a debugger then use this function sorrounding the fatal error to get the "fatal stack". Check the code and example below that explains better how to use it:

// Give an extra parameter to the filename
// to save multiple log files
function _fatalog_($extra = false)
{
    static $last_extra;

    // CHANGE THIS TO: A writeable filepath in your system...
    $filepath = '/var/www/html/sites/default/files/fatal-'.($extra === false ? $last_extra : $extra).'.log';

    if ($extra===false) {
        unlink($filepath);
    } else {
        // we write a log file with the debug info
        file_put_contents($filepath, json_encode(debug_backtrace()));
        // saving last extra parameter for future unlink... if possible...
        $last_extra = $extra;
    }
}

Here's an example of how to use it:

// A function which will produce a fatal error
function fatal_example()
{
    _fatalog_(time()); // writing the log
    $some_fatal_code = array()/3; // fatality!
    _fatalog_(); // if we get here then delete last file log
}

Finally to read the contents of the log...

var_dump(json_decode(file_get_contents('/path/to-the-fatal.log')));

Hope that helps!

怎樣才叫好 2024-08-04 18:59:23

PHP5 中的 set_error_handler() + debug_backtrace() + debug_print_backtrace()

set_error_handler() + debug_backtrace() + debug_print_backtrace() in PHP5

ら栖息 2024-08-04 18:59:11
$backtrace = debug_backtrace();

我写了一个 不久前关于回溯的小文章

$backtrace = debug_backtrace();

i wrote a little article about backtracing a while back

a√萤火虫的光℡ 2024-08-04 18:58:59

这就是你如何做到的:

set_error_handler(function($errorType){
    if(error_reporting() & $errorType){
        ?><pre><?
        debug_print_backtrace();
        ?></pre><?
    }
}) ;

它需要 PHP 5.3+,因为它使用闭包。 如果您需要较低的 PHP 支持,只需将闭包转换为普通函数即可。

This is how you do it:

set_error_handler(function($errorType){
    if(error_reporting() & $errorType){
        ?><pre><?
        debug_print_backtrace();
        ?></pre><?
    }
}) ;

It requires PHP 5.3+ since it uses a closure. If you need lower PHP support just convert the closure to a normal function.

落日海湾 2024-08-04 18:58:49

作为 php 调试扩展,有 XdebugPHP DBG. 每一种都有其优点和缺点。

As php debug extensions, there is Xdebug and PHP DBG. Each one has its advantages and disadvantages.

夜雨飘雪 2024-08-04 18:58:39

您可以使用 debug_backtrace

You can use debug_backtrace

记忆消瘦 2024-08-04 18:58:29

我只是尝试在有问题的行设置一个包含 debug_backtrace() 内容的会话变量,然后使用 register_shutdown_function() 打印它。 工作起来就像一个魅力。

I just tried setting a session variable containing the contents of debug_backtrace() at the offending line, then printing it using register_shutdown_function(). Worked like a charm.

不及他 2024-08-04 18:58:20

PHP 错误

这是针对用 PHP 编写的 PHP 的更好的错误报告。 不需要额外的扩展!

对于正常的 AJAXy 请求(处于暂停状态),所有错误都显示在浏览器中,使用起来很简单。 然后,所有错误都会为您提供整个堆栈跟踪的回溯和代码上下文,包括函数参数、服务器变量。

您需要做的就是包含一个文件并调用该函数(在代码的开头),例如

require('php_error.php');
\php_error\reportErrors();

请参阅屏幕截图:

PHP 错误 | 改进 PHP 错误报告 - 回溯的屏幕截图
PHP 错误| 改进 PHP 的错误报告 - 回溯的屏幕截图
PHP 错误| 改进 PHP 的错误报告 - backtrace 的屏幕截图

GitHub:https://github。 com/JosephLenton/PHP-Error

我的分支(带有额外的修复): https:/ /github.com/kenorb-contrib/PHP-Error

调试 PHP

A 类完整的 PHP 调试器类,支持异常、错误、警报(来自用户)、代码行和突出显示标志。

用法示例:

 <?php
        include( dirname(dirname(__FILE__))  . '/src/Debug.php' );
        //Catch all
        Debug::register();

        //Generate an errors
        if( this_function_does_not_exists( ) )
        {
            return false;
        }
    ?>

PHP 中的错误处理

下面的示例显示了通过触发错误并使用用户定义的函数处理它们来处理内部异常:

更短的方法 (PHP):

<?php
function e($number, $msg, $file, $line, $vars) {
   print_r(debug_backtrace());
   die();
}
set_error_handler('e');

更长的方法 (PHP):

// set to the user defined error handler
$old_error_handler = set_error_handler("myErrorHandler");

// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
    if (!(error_reporting() & $errno)) {
        // This error code is not included in error_reporting
        return;
    }

    switch ($errno) {
    case E_USER_ERROR:
        echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
        echo "  Fatal error on line $errline in file $errfile";
        echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
        echo "Aborting...<br />\n";
        var_dump(debug_backtrace());
        exit(1);
        break;

    case E_USER_WARNING:
        echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
        break;

    case E_USER_NOTICE:
        echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
        break;

    default:
        echo "Unknown error type: [$errno] $errstr<br />\n";
        break;
    }

    /* Don't execute PHP internal error handler */
    return true;
}

请参阅: http://www.php.net/manual/en/function.set-error-handler。 php

注意:一次只能有一个错误异常。 当您调用 set_error_handler() 函数时,它将返回旧错误处理程序的名称。 您可以存储它并从错误处理程序中自行调用它 - 从而允许您拥有多个错误处理程序。


XDebug

对于更高级的解决方案,您可以使用 PHP 的 XDebug 扩展。

默认情况下,当加载 XDebug 时,它应该自动显示回溯,以防出现任何致命错误。 或者您跟踪文件(xdebug.auto_trace)以对整个请求进行非常大的回溯,或者进行分析(xdebug.profiler_enable)或 其他设置。 如果跟踪文件太大,您可以使用 xdebug_start_trace() 和 xdebug_stop_trace() 转储部分跟踪。

安装

使用 PECL:

pecl install xdebug

在 Linux 上:

sudo apt-get install php5-xdebug

在 Mac(使用 Homebrew)上:

brew tap josegonzalez/php
brew search xdebug
php53-xdebug

我的配置示例:

[xdebug]

; Extensions
extension=xdebug.so
; zend_extension="/YOUR_PATH/php/extensions/no-debug-non-zts-20090626/xdebug.so"
; zend_extension="/Applications/MAMP/bin/php/php5.3.20/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so" ; MAMP

; Data
xdebug.show_exception_trace=1       ; bool: Show a stack trace whenever an exception is raised.
xdebug.collect_vars = 1             ; bool: Gather information about which variables are used in a certain scope.
xdebug.show_local_vars=1            ; int: Generate stack dumps in error situations.
xdebug.collect_assignments=1        ; bool: Controls whether Xdebug should add variable assignments to function traces.
xdebug.collect_params=4             ; int1-4: Collect the parameters passed to functions when a function call is recorded.
xdebug.collect_return=1             ; bool: Write the return value of function calls to the trace files.
xdebug.var_display_max_children=256 ; int: Amount of array children and object's properties are shown.
xdebug.var_display_max_data=1024    ; int: Max string length that is shown when variables are displayed.
xdebug.var_display_max_depth=3      ; int: How many nested levels of array/object elements are displayed.
xdebug.show_mem_delta=0             ; int: Show the difference in memory usage between function calls.

; Trace
xdebug.auto_trace=0                 ; bool: The tracing of function calls will be enabled just before the script is run.
xdebug.trace_output_dir="/var/log/xdebug" ; string: Directory where the tracing files will be written to.
xdebug.trace_output_name="%H%R-%s-%t"     ; string: Name of the file that is used to dump traces into.

; Profiler
xdebug.profiler_enable=0            ; bool: Profiler which creates files read by KCacheGrind.
xdebug.profiler_output_dir="/var/log/xdebug"  ; string: Directory where the profiler output will be written to.
xdebug.profiler_output_name="%H%R-%s-%t"      ; string: Name of the file that is used to dump traces into.
xdebug.profiler_append=0            ; bool: Files will not be overwritten when a new request would map to the same file.

; CLI
xdebug.cli_color=1                  ; bool: Color var_dumps and stack traces output when in CLI mode.

; Remote debugging
xdebug.remote_enable=off            ; bool: Try to contact a debug client which is listening on the host and port.
xdebug.remote_autostart=off         ; bool: Start a remote debugging session even GET/POST/COOKIE variable is not present.
xdebug.remote_handler=dbgp          ; select: php3/gdb/dbgp: The DBGp protocol is the only supported protocol.
xdebug.remote_host=localhost        ; string: Host/ip where the debug client is running.
xdebug.remote_port=9000             ; integer: The port to which Xdebug tries to connect on the remote host.
xdebug.remote_mode=req              ; select(req,jit): Selects when a debug connection is initiated.
xdebug.idekey="xdebug-cli"          ; string: IDE Key Xdebug which should pass on to the DBGp debugger handler.
xdebug.remote_log="/var/log/xdebug.log" ; string: Filename to a file to which all remote debugger communications are logged.

Drupal 6&7

启用 Devel:

/**
 * Implements hook_watchdog().
 */
function foo_watchdog($log_entry) {
  if ($log_entry['type'] == 'php' && $log_entry['severity'] <= WATCHDOG_WARNING) {
    function_exists('dd') && dd(debug_backtrace());
  }
}

以上函数会将每个错误的回溯记录记录到临时文件中(默认为 /tmp/drupal_debug.txt)。

或者通过以下方式找到该文件:drush eval "echo file_directory_temp() . '/drupal_debug.txt'

如果不启用 Devel,请使用旧式方法:var_dump(debug_backtrace()); 而不是 dd()

PHP Error

This is better error reporting for PHP written in PHP. No extra extensions are required!

It is trivial to use where all errors are displayed in the browser for normal, AJAXy requests (in paused state). Then all errors provides you with a backtrace and code context across the whole stack trace, including function arguments, server variables.

All you need to do is to include one single file and call the function (at the beginning on your code), e.g.

require('php_error.php');
\php_error\reportErrors();

See the screenshots:

PHP Error | Improve Error Reporting for PHP - screenshot of backtrace
PHP Error | Improve Error Reporting for PHP - screenshot of backtrace
PHP Error | Improve Error Reporting for PHP - screenshot of backtrace

GitHub: https://github.com/JosephLenton/PHP-Error

My fork (with extra fixes): https://github.com/kenorb-contrib/PHP-Error

Debug PHP class

A complete PHP debugger class, with support for Exception, Errors, Alerts ( from user), code lines and highlight flags.

Example usage:

 <?php
        include( dirname(dirname(__FILE__))  . '/src/Debug.php' );
        //Catch all
        Debug::register();

        //Generate an errors
        if( this_function_does_not_exists( ) )
        {
            return false;
        }
    ?>

Error Handling in PHP

The example below shows the handling of internal exceptions by triggering errors and handling them with a user defined function:

Shorter way (PHP):

<?php
function e($number, $msg, $file, $line, $vars) {
   print_r(debug_backtrace());
   die();
}
set_error_handler('e');

Longer way (PHP):

// set to the user defined error handler
$old_error_handler = set_error_handler("myErrorHandler");

// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
    if (!(error_reporting() & $errno)) {
        // This error code is not included in error_reporting
        return;
    }

    switch ($errno) {
    case E_USER_ERROR:
        echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
        echo "  Fatal error on line $errline in file $errfile";
        echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
        echo "Aborting...<br />\n";
        var_dump(debug_backtrace());
        exit(1);
        break;

    case E_USER_WARNING:
        echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
        break;

    case E_USER_NOTICE:
        echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
        break;

    default:
        echo "Unknown error type: [$errno] $errstr<br />\n";
        break;
    }

    /* Don't execute PHP internal error handler */
    return true;
}

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

Note: You can only have one error exception at a time. When you call the set_error_handler() function it will return the name of the old error handler. You can store this and call it yourself from your error handler – thus allowing you to have multiple error handlers.


XDebug

For more advanced solution, you can use XDebug extension for PHP.

By default when XDebug is loaded, it should show you automatically the backtrace in case of any fatal error. Or you trace into file (xdebug.auto_trace) to have a very big backtrace of the whole request or do the profiling (xdebug.profiler_enable) or other settings. If the trace file is too big, you can use xdebug_start_trace() and xdebug_stop_trace() to dump the partial trace.

Installation

Using PECL:

pecl install xdebug

On Linux:

sudo apt-get install php5-xdebug

On Mac (with Homebrew):

brew tap josegonzalez/php
brew search xdebug
php53-xdebug

Example of mine configuration:

[xdebug]

; Extensions
extension=xdebug.so
; zend_extension="/YOUR_PATH/php/extensions/no-debug-non-zts-20090626/xdebug.so"
; zend_extension="/Applications/MAMP/bin/php/php5.3.20/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so" ; MAMP

; Data
xdebug.show_exception_trace=1       ; bool: Show a stack trace whenever an exception is raised.
xdebug.collect_vars = 1             ; bool: Gather information about which variables are used in a certain scope.
xdebug.show_local_vars=1            ; int: Generate stack dumps in error situations.
xdebug.collect_assignments=1        ; bool: Controls whether Xdebug should add variable assignments to function traces.
xdebug.collect_params=4             ; int1-4: Collect the parameters passed to functions when a function call is recorded.
xdebug.collect_return=1             ; bool: Write the return value of function calls to the trace files.
xdebug.var_display_max_children=256 ; int: Amount of array children and object's properties are shown.
xdebug.var_display_max_data=1024    ; int: Max string length that is shown when variables are displayed.
xdebug.var_display_max_depth=3      ; int: How many nested levels of array/object elements are displayed.
xdebug.show_mem_delta=0             ; int: Show the difference in memory usage between function calls.

; Trace
xdebug.auto_trace=0                 ; bool: The tracing of function calls will be enabled just before the script is run.
xdebug.trace_output_dir="/var/log/xdebug" ; string: Directory where the tracing files will be written to.
xdebug.trace_output_name="%H%R-%s-%t"     ; string: Name of the file that is used to dump traces into.

; Profiler
xdebug.profiler_enable=0            ; bool: Profiler which creates files read by KCacheGrind.
xdebug.profiler_output_dir="/var/log/xdebug"  ; string: Directory where the profiler output will be written to.
xdebug.profiler_output_name="%H%R-%s-%t"      ; string: Name of the file that is used to dump traces into.
xdebug.profiler_append=0            ; bool: Files will not be overwritten when a new request would map to the same file.

; CLI
xdebug.cli_color=1                  ; bool: Color var_dumps and stack traces output when in CLI mode.

; Remote debugging
xdebug.remote_enable=off            ; bool: Try to contact a debug client which is listening on the host and port.
xdebug.remote_autostart=off         ; bool: Start a remote debugging session even GET/POST/COOKIE variable is not present.
xdebug.remote_handler=dbgp          ; select: php3/gdb/dbgp: The DBGp protocol is the only supported protocol.
xdebug.remote_host=localhost        ; string: Host/ip where the debug client is running.
xdebug.remote_port=9000             ; integer: The port to which Xdebug tries to connect on the remote host.
xdebug.remote_mode=req              ; select(req,jit): Selects when a debug connection is initiated.
xdebug.idekey="xdebug-cli"          ; string: IDE Key Xdebug which should pass on to the DBGp debugger handler.
xdebug.remote_log="/var/log/xdebug.log" ; string: Filename to a file to which all remote debugger communications are logged.

Drupal 6&7

With Devel enabled:

/**
 * Implements hook_watchdog().
 */
function foo_watchdog($log_entry) {
  if ($log_entry['type'] == 'php' && $log_entry['severity'] <= WATCHDOG_WARNING) {
    function_exists('dd') && dd(debug_backtrace());
  }
}

Above function will log the backtraces on each error into temporary file (/tmp/drupal_debug.txt by default).

Or locate the file via: drush eval "echo file_directory_temp() . '/drupal_debug.txt'.

Without Devel enabled, use old school approach: var_dump(debug_backtrace()); instead of dd().

灰色世界里的红玫瑰 2024-08-04 18:58:13

我用于安装产生回溯的错误处理程序的脚本:

<?php
function process_error_backtrace($errno, $errstr, $errfile, $errline, $errcontext) {
    if(!(error_reporting() & $errno))
        return;
    switch($errno) {
    case E_WARNING      :
    case E_USER_WARNING :
    case E_STRICT       :
    case E_NOTICE       :
    case E_USER_NOTICE  :
        $type = 'warning';
        $fatal = false;
        break;
    default             :
        $type = 'fatal error';
        $fatal = true;
        break;
    }
    $trace = array_reverse(debug_backtrace());
    array_pop($trace);
    if(php_sapi_name() == 'cli') {
        echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
        foreach($trace as $item)
            echo '  ' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()' . "\n";
    } else {
        echo '<p class="error_backtrace">' . "\n";
        echo '  Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
        echo '  <ol>' . "\n";
        foreach($trace as $item)
            echo '    <li>' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()</li>' . "\n";
        echo '  </ol>' . "\n";
        echo '</p>' . "\n";
    }
    if(ini_get('log_errors')) {
        $items = array();
        foreach($trace as $item)
            $items[] = (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()';
        $message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
        error_log($message);
    }
    if($fatal)
        exit(1);
}

set_error_handler('process_error_backtrace');
?>

警告:它无法影响各种'PHP致命错误',因为 Zend 明智地决定这些将忽略 set_error_handler()。 所以你仍然会得到无用的仅最终位置错误。

My script for installing an error handler that produces a backtrace:

<?php
function process_error_backtrace($errno, $errstr, $errfile, $errline, $errcontext) {
    if(!(error_reporting() & $errno))
        return;
    switch($errno) {
    case E_WARNING      :
    case E_USER_WARNING :
    case E_STRICT       :
    case E_NOTICE       :
    case E_USER_NOTICE  :
        $type = 'warning';
        $fatal = false;
        break;
    default             :
        $type = 'fatal error';
        $fatal = true;
        break;
    }
    $trace = array_reverse(debug_backtrace());
    array_pop($trace);
    if(php_sapi_name() == 'cli') {
        echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
        foreach($trace as $item)
            echo '  ' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()' . "\n";
    } else {
        echo '<p class="error_backtrace">' . "\n";
        echo '  Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
        echo '  <ol>' . "\n";
        foreach($trace as $item)
            echo '    <li>' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()</li>' . "\n";
        echo '  </ol>' . "\n";
        echo '</p>' . "\n";
    }
    if(ini_get('log_errors')) {
        $items = array();
        foreach($trace as $item)
            $items[] = (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()';
        $message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
        error_log($message);
    }
    if($fatal)
        exit(1);
}

set_error_handler('process_error_backtrace');
?>

Caveat: it is powerless to affect various 'PHP Fatal Errors', since Zend in their wisdom decided that these would ignore set_error_handler(). So you still get useless final-location-only errors with those.

左秋 2024-08-04 18:58:03

Xdebug 打印错误的回溯表,您无需编写任何 PHP 代码来实现它。

缺点是您必须将其安装为 PHP 扩展。

Xdebug prints a backtrace table on errors, and you don't have to write any PHP code to implement it.

Downside is you have to install it as a PHP extension.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文