如何让PHP在出错时产生回溯?

尝试使用其默认仅限当前行错误消息来debuggingPHP是非常可怕的。 如何在发生错误时让PHP产生回溯(堆栈跟踪)?

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

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

我的脚本安装产生回溯的error handling程序:

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

警告:由于Zend在他们的智慧中决定忽略set_error_handler() ,所以无法影响各种“PHP致命错误” 。 所以你仍然得到无用的最终位置唯一的错误。

PHP错误

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

在正常的AJAXy请求(处于暂停状态)中,在浏览器中显示所有错误的地方是微不足道的。 然后,所有错误都会为整个堆栈跟踪提供回溯和代码上下文,包括函数参数,服务器variables。

所有你需要做的就是包含一个单一的文件,并调用函数(在你的代码的开始),例如

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

看截图:

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

主页: http : //phperror.net/

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

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

debuggingPHP类

一个完整的PHPdebugging器类,支持Exception,Errors,Alerts(来自用户),代码行和高亮标志。

用法示例:

  <?php include( dirname(dirname(__FILE__)) . '/src/Debug.php' ); //Catch all Debug::register(); //Generate an errors if( this_function_does_not_exists( ) ) { return false; } ?> 

PHP中的error handling

下面的例子显示了通过触发错误和使用用户定义的函数处理内部exception的处理:

更短的方式(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

注意:一次只能有一个错误exception。 当您调用set_error_handler()函数时,它将返回旧的error handling程序的名称。 你可以存储这个,并从你的error handling程序中自己调用它 – 这样就可以让你有多个error handling程序。


的XDebug

对于更高级的解决scheme,您可以使用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(与自制软件):

 brew tap josegonzalez/php brew search xdebug php53-xdebug 

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

启用了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()); } } 

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

或者通过: drush eval "echo file_directory_temp() . '/drupal_debug.txt'find该文件。

没有启用Devel,使用旧的方法: var_dump(debug_backtrace()); 而不是dd()

我只是尝试在违规行中设置包含debug_backtrace()的内容的会话variables,然后使用register_shutdown_function()将其打印出来。 像魅力一样工作。

你可以使用debug_backtrace

作为PHPdebugging扩展,有Xdebug和PHP的DBG 。 每个人都有其优点和缺点。

PHP错误会给你一个堆栈跟踪你的错误,并比xDebug更漂亮。

它也适用于Ajax请求。

 $backtrace = debug_backtrace(); 

我写了一篇关于回溯一段时间的文章

这是你如何做到的:

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

它需要PHP 5.3+,因为它使用闭包。 如果您需要较低的PHP支持,只需将闭包转换为一个正常的函数。

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

如果你不能安装debugging器,那么使用这个function来避免致命的错误来获得“致命的堆栈”。 查看下面的代码和示例,更好地说明如何使用它:

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

希望有所帮助!

PHP的DeBugger也做了一个类似PHP错误的后面跟踪更多的选项。
如果你想用set_error_handlerdebug_backtrace来轻松创build你自己的

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

另外请注意,对于回溯中的内部堆栈,某些键不会被设置。 如果你有所有错误,请务必检查密钥是否存在