¿Cómo puedo hacer que PHP produzca un backtrace sobre errores?


Intentar depurar PHP usando sus mensajes de error predeterminados de solo línea actual es horrible. ¿Cómo puedo hacer que PHP produzca una traza inversa (stack trace) cuando se producen errores?

Author: chaos, 2009-07-21

12 answers

Xdebug imprime una tabla de traza inversa sobre los errores, y no tiene que escribir ningún código PHP para implementarlo.

El inconveniente es que tiene que instalarlo como una extensión PHP.

 45
Author: patcoll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-21 13:50:37

Mi script para instalar un manejador de errores que produce una traza inversa:

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

Advertencia: es impotente para afectar varios 'Errores Fatales de PHP', ya que Zend en su sabiduría decidió que estos ignorarían set_error_handler(). Así que aún obtienes errores inútiles de solo ubicación final con esos.

 45
Author: chaos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-21 13:45:58

Error de PHP

Este es un mejor reporte de errores para PHP escrito en PHP. No se requieren extensiones adicionales!

Es trivial usar donde se muestran todos los errores en el navegador para solicitudes AJAXy normales (en estado pausado). A continuación, todos los errores le proporciona una traza inversa y un contexto de código en todo el seguimiento de la pila, incluidos los argumentos de la función y las variables del servidor.

Todo lo que necesita hacer es incluir un solo archivo y llamar a la función (en el a partir de su código), por ejemplo,

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

Ver las capturas de pantalla:

Error de PHP / Mejorar el informe de errores para PHP-captura de pantalla de backtrace Error de PHP / Mejorar el informe de errores para PHP-captura de pantalla de backtrace Error de PHP / Mejorar el informe de errores para PHP-captura de pantalla de backtrace

Página de Inicio: http://phperror.net/

[17]} GitHub: https://github.com/JosephLenton/PHP-Error

Mi fork (con correcciones adicionales): https://github.com/kenorb-contrib/PHP-Error

Depurar PHP clase

Una clase completa de depurador PHP, con soporte para Excepciones, Errores, Alertas (de usuario), líneas de código y banderas de resaltado.

Ejemplo de uso:

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

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

Manejo de errores en PHP

El siguiente ejemplo muestra el manejo de excepciones internas activando errores y manejándolos con una función definida por el usuario:

Camino más corto (PHP):

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

Camino más largo (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;
}

Véase: http://www.php.net/manual/en/function.set-error-handler.php

Nota: Solo puede tener una excepción de error a la vez. Cuando si llamas a la función set_error_handler () devolverá el nombre del antiguo manejador de errores. Puede almacenar esto y llamarlo usted mismo desde su controlador de errores, lo que le permite tener varios controladores de errores.


XDebug

Para una solución más avanzada, puede usar la extensión XDebug para PHP.

De forma predeterminada, cuando se carga XDebug, debe mostrar automáticamente la traza inversa en caso de cualquier error fatal. O se rastrea en el archivo (xdebug.auto_trace) a tener un backtrace muy grande de toda la solicitud o hacer el perfil (xdebug.profiler_enable) o otros ajustes. Si el archivo de seguimiento es demasiado grande, puede usar xdebug_start_trace() y xdebug_stop_trace () para volcar el seguimiento parcial.

Instalación

Usando PECL:

pecl install xdebug

En Linux:

sudo apt-get install php5-xdebug

En Mac (con Homebrew):

brew tap josegonzalez/php
brew search xdebug
php53-xdebug

Ejemplo de configuración de la mina:

[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

Con 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());
  }
}

La función anterior registrará las retrotracciones de cada error en un archivo temporal (/tmp/drupal_debug.txt por defecto).

O localice el archivo a través de: drush eval "echo file_directory_temp() . '/drupal_debug.txt'.

Sin Devel habilitado, use el enfoque de la vieja escuela: var_dump(debug_backtrace()); en lugar de dd().

 24
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-13 09:03:45

Acabo de intentar establecer una variable de sesión que contiene el contenido de debug_backtrace() en la línea ofensiva, luego imprimirlo usando register_shutdown_function(). Funcionó a las mil maravillas.

 7
Author: Tim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-22 20:06:43
 3
Author: Mythica,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-30 13:45:50

Como extensiones de depuración de php, hay Xdebug y PHP DBG. Cada uno tiene sus ventajas y desventajas.

 2
Author: T0xicCode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-31 02:57:56

PHP Error le dará un seguimiento de pila para sus errores, y es mucho más bonito que xDebug.

También funcionará para solicitudes ajax también.

 2
Author: JL235,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-05 23:59:30

Así es como lo haces:

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

Requiere PHP 5.3 + ya que utiliza un cierre. Si necesita un menor soporte de PHP, simplemente convierta el cierre a una función normal.

 2
Author: GetFree,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-15 23:09:21
$backtrace = debug_backtrace();

Escribí un pequeño artículo acerca de volver atrás un tiempo

 1
Author: smoove,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-22 02:10:02

set_error_handler() + debug_backtrace() + debug_print_backtrace() en PHP5

 1
Author: Lukasz Czerwinski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-10 17:25:55

Si no puede instalar un depurador, utilice esta función que rodea el error fatal para obtener la "pila fatal". Compruebe el código y el ejemplo a continuación que explica mejor cómo usarlo:

// 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;
    }
}

Aquí hay un ejemplo de cómo usarlo:

// 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
}

Finalmente para leer el contenido del registro...

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

¡Espero que eso ayude!

 1
Author: Beto Aveiga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 16:17:04

PHP DeBugger también hace un back trace similar al Error de PHP con más opciones.
Si lo desea puede hacer fácilmente el suyo propio con set_error_handler y 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
    }
}

También tenga en cuenta que para pilas internas en el backtrace algunas de las claves no se establecerán. Asegúrese de verificar si la clave existe antes de hacer algo con ella si tiene todos los errores en:)

 0
Author: Yamiko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-03 21:00:21