web-dev-qa-db-fra.com

Comment puis-je avoir PHP produire une trace des erreurs?

Essayer de déboguer PHP - utiliser ses messages d'erreur par défaut pour la ligne courante uniquement est horrible. Comment puis-je obtenir PHP, de produire une trace (trace de pile) lorsque des erreurs sont générées?

48
chaos

Xdebug affiche une table de trace sur les erreurs et vous n'avez pas à écrire de code PHP pour l'implémenter.

L'inconvénient est que vous devez l'installer en tant qu'extension PHP.

46
patcoll

Mon script pour installer un gestionnaire d’erreur produisant une trace:

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

Mise en garde: il est impuissant d'affecter divers 'PHP Fatal Errors' , car Zend, dans leur sagesse, a décidé qu'ils ignoreraient set_error_handler(). Vous obtenez donc toujours des erreurs inutiles d'emplacement final uniquement.

46
chaos

PHP Erreur

C'est un meilleur rapport d'erreur pour PHP écrit en PHP. Aucune extension supplémentaire n'est requise!

Il est facile à utiliser lorsque toutes les erreurs sont affichées dans le navigateur pour les requêtes AJAXy normales (en état de pause). Ensuite, toutes les erreurs vous fournissent un fond de trace et un contexte de code pour l’ensemble de la trace de la pile, y compris les arguments de fonction et les variables de serveur.

Tout ce que vous avez à faire est d'inclure un seul fichier et d'appeler la fonction (au début de votre code), par exemple.

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

Voir les 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

Mon fork (avec des corrections supplémentaires): https://github.com/kenorb-contrib/PHP-Error

Déboguer PHP class

Une classe complète de débogueur PHP, avec prise en charge des exceptions, des erreurs, des alertes (de l'utilisateur), des lignes de code et des indicateurs de surbrillance.

Exemple d'utilisation:

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

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

Traitement des erreurs en PHP

L'exemple ci-dessous illustre le traitement des exceptions internes en déclenchant des erreurs et en les gérant avec une fonction définie par l'utilisateur:

Plus court chemin (PHP):

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

Plus long chemin (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;
}

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

Remarque: Vous ne pouvez avoir qu'une seule exception d'erreur à la fois. Lorsque vous appelez la fonction set_error_handler (), elle renvoie le nom de l'ancien gestionnaire d'erreurs. Vous pouvez la stocker et l'appeler vous-même à partir de votre gestionnaire d'erreurs - vous permettant ainsi d'avoir plusieurs gestionnaires d'erreurs.


XDebug

Pour une solution plus avancée, vous pouvez utiliser XDebug extension pour PHP.

Par défaut, lorsque XDebug est chargé, il devrait vous montrer automatiquement la trace en cas d'erreur fatale. Ou vous tracez dans le fichier (xdebug.auto_trace) pour avoir une très grande trace de toute la demande ou faites le profilage (xdebug.profiler_enable) ou autres paramètres . Si le fichier de trace est trop volumineux, vous pouvez utiliser xdebug_start_trace () et xdebug_stop_trace () pour vider la trace partielle.

Installation

Utilisation de PECL:

pecl install xdebug

Sous Linux:

Sudo apt-get install php5-xdebug

Sur Mac (avec Homebrew):

brew tap josegonzalez/php
brew search xdebug
php53-xdebug

Exemple de configuration de la mine:

[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 et 7

Avec Devel activé:

/**
 * 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 fonction ci-dessus enregistre les traces de chaque erreur dans un fichier temporaire (/tmp/drupal_debug.txt par défaut).

Ou localisez le fichier via: drush eval "echo file_directory_temp() . '/drupal_debug.txt'.

Sans que Devel soit activé, utilisez l'approche old school: var_dump(debug_backtrace()); au lieu de dd().

26
kenorb

Je viens d'essayer de définir une variable de session contenant le contenu de debug_backtrace () sur la ligne incriminée, puis de l'imprimer à l'aide de register_shutdown_function (). Travaillé comme un charme. 

7
Tim

Vous pouvez utiliser debug_backtrace

3
Mythica

En tant qu'extensions de débogage php, il existe Xdebug et PHP DBG . Chacun a ses avantages et ses inconvénients.

2
T0xicCode

Voici comment vous le faites:

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

Cela nécessite PHP 5.3+ car il utilise une fermeture. Si vous avez besoin d'un support inférieur PHP, il suffit de convertir la fermeture en une fonction normale.

2
GetFree
$backtrace = debug_backtrace();

j'ai écrit un petit article sur le retour en arrière

1
smoove

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

1

Si vous ne pouvez pas installer de débogueur, utilisez cette fonction en corrigeant l'erreur fatale pour obtenir la "pile fatale". Vérifiez le code et l'exemple ci-dessous qui explique mieux comment l'utiliser:

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

Voici un exemple d'utilisation:

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

Enfin pour lire le contenu du journal ...

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

J'espère que cela pourra aider!

1
Beto Aveiga

PHP DeBugger effectue également une trace arrière similaire à PHP Erreur avec davantage d'options .
Si vous voulez, vous pouvez facilement créer le vôtre avec set_error_handler et 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
    }
}

Notez également que pour les piles internes dans la trace arrière, certaines des clés ne seront pas définies. Assurez-vous de vérifier si la clé existe avant de faire quelque chose avec si vous avez toutes les erreurs sur :)

0
Yamiko