Как я могу заставить PHP создавать обратную трассировку при ошибках?


Попытка отладки PHP с использованием сообщений об ошибках только в текущей строке по умолчанию ужасна. Как я могу заставить PHP создавать обратную трассировку (трассировку стека) при возникновении ошибок?

Author: chaos, 2009-07-21

12 answers

Xdebug выводит таблицу отслеживания ошибок, и вам не нужно писать какой-либо PHP-код для ее реализации.

Недостатком является то, что вы должны установить его как расширение PHP.

 45
Author: patcoll, 2009-07-21 13:50:37

Мой скрипт для установки обработчика ошибок, который создает обратную трассировку:

<?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(). Таким образом, вы все равно получаете бесполезные ошибки только для конечного местоположения.

 45
Author: chaos, 2009-07-21 13:45:58

Ошибка PHP

Это лучший отчет об ошибках для PHP, написанный на PHP. Никаких дополнительных расширений не требуется!

Тривиально использовать, когда все ошибки отображаются в браузере для обычных запросов AJAXy (в приостановленном состоянии). Затем все ошибки предоставляют вам обратную трассировку и контекст кода по всей трассировке стека, включая аргументы функций, переменные сервера.

Все, что вам нужно сделать, это включить один единственный файл и вызвать функцию (в начиная с вашего кода), например

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

Домашняя страница: http://phperror.net/

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

Моя вилка (с дополнительными исправлениями): https://github.com/kenorb-contrib/PHP-Error

Отладка 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):

<?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) или другие настройки . Если файл трассировки слишком велик, вы можете использовать xdebug_start_trace() и xdebug_stop_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.

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'.

Без включенной разработки используйте подход старой школы: var_dump(debug_backtrace()); вместо dd().

 24
Author: kenorb, 2016-04-13 09:03:45

Я только что попытался установить переменную сеанса, содержащую содержимое debug_backtrace(), в оскорбительной строке, а затем распечатать ее с помощью register_shutdown_function(). Сработало как заклинание.

 7
Author: Tim, 2012-10-22 20:06:43

Вы можете использовать debug_backtrace для отладки

 3
Author: Mythica, 2009-07-30 13:45:50

В качестве расширений отладки php есть Xdebug и PHP DBG. У каждого из них есть свои преимущества и недостатки.

 2
Author: T0xicCode, 2009-07-31 02:57:56

Ошибка PHP даст вам трассировку стека для ваших ошибок и намного красивее, чем xDebug.

Это также будет работать и для ajax-запросов.

 2
Author: JL235, 2012-07-05 23:59:30

Вот как вы это делаете:

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

Для этого требуется PHP 5.3+, так как он использует замыкание. Если вам нужна более низкая поддержка PHP, просто преобразуйте закрытие в обычную функцию.

 2
Author: GetFree, 2013-06-15 23:09:21
$backtrace = debug_backtrace();

Я написал небольшую статью о возврате некоторое время назад

 1
Author: smoove, 2009-07-22 02:10:02

set_error_handler() + debug_backtrace() + debug_print_backtrace() в PHP5

 1
Author: Lukasz Czerwinski, 2015-11-10 17:25:55

Если вы не можете установить отладчик, используйте эту функцию, чтобы избежать фатальной ошибки, чтобы получить "фатальный стек". Проверьте код и приведенный ниже пример, который лучше объясняет, как его использовать:

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

Надеюсь, это поможет!

 1
Author: Beto Aveiga, 2016-09-28 16:17:04

Отладчик PHP также выполняет обратную трассировку, аналогичную ошибке 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
    }
}

Также обратите внимание, что для внутренних стеков в обратном пути некоторые ключи не будут установлены. Обязательно проверьте, существует ли ключ, прежде чем что-то с ним делать, если у вас есть все ошибки:)

 0
Author: Yamiko, 2012-11-03 21:00:21