代码之家  ›  专栏  ›  技术社区  ›  chaos

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

  •  48
  • chaos  · 技术社区  · 16 年前

    11 回复  |  直到 16 年前
        1
  •  49
  •   chaos    16 年前

    <?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 Fatal Errors' ,因为Zend以他们的智慧决定这些将被忽略 set_error_handler() . 所以你仍然会得到无用的最终位置错误。

        2
  •  47
  •   patcoll    16 年前

    Xdebug 在错误上打印回溯表,您不必编写任何PHP代码来实现它。

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

        3
  •  28
  •   kenorb    6 年前

    PHP Error

    您只需包含一个文件并调用函数(在代码开头),例如。

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

    请参见屏幕截图:

    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

    https://github.com/kenorb-contrib/PHP-Error

    Debug PHP

    一个完整的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
    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

    XDebug PHP的扩展。

    默认情况下,加载XDebug时,如果出现任何致命错误,它会自动显示回溯。或者您跟踪到文件(xdebug.auto_trace)中,以对整个请求进行非常大的回溯,或者进行分析(xdebug.profiler_enable),或者 other settings . 如果跟踪文件太大,可以使用xdebug\u start\u trace()和xdebug\u stop\u trace()转储部分跟踪。

    装置

    使用PECL:

    pecl install xdebug
    

    在Linux上:

    sudo apt-get install php5-xdebug
    

    在Mac上(使用自制软件):

    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.
    

    Drupal6&7.

    /**
     * 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() .

        4
  •  8
  •   Tim    13 年前

    我只是尝试在有问题的行设置一个包含debug\u backtrace()内容的会话变量,然后使用register\u shutdown\u function()打印它。工作得很有魅力。

        5
  •  3
  •   chaos    16 年前

    你可以用 debug_backtrace

        6
  •  2
  •   chaos    16 年前

    Xdebug PHP DBG . 每一种都有其优缺点。

        7
  •  2
  •   GetFree    12 年前

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

        8
  •  1
  •   chaos    16 年前
    $backtrace = debug_backtrace();
    

    我写了一封信 little article about backtracing 不久前

        9
  •  1
  •   kenorb    9 年前

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

        10
  •  1
  •   Beto Aveiga    9 年前

    // 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')));
    

    希望有帮助!

        11
  •  0
  •   Yamiko    13 年前

    PHP DeBugger 还做了一个类似于PHP错误的回溯跟踪,提供了更多选项。
    set_error_handler 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
        }
    }
    

    还请注意,对于回溯中的内部堆栈,将不会设置一些键。如果出现以下所有错误,请确保在使用密钥之前检查该密钥是否存在:)

    推荐文章