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

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

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

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

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

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

Ошибка PHP

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

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

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

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

Смотрите скриншоты:

Ошибка PHP | Улучшение отчетов об ошибках для PHP - снимок экрана backtrace Ошибка PHP | Улучшение отчетов об ошибках для PHP - снимок экрана backtrace Ошибка PHP | Улучшение отчетов об ошибках для PHP - снимок экрана backtrace

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

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

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

Отладка PHP- класса

Полный класс отладчика PHP с поддержкой 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

В приведенном ниже примере показана обработка внутренних исключений путем запуска ошибок и обработки их с помощью определенной пользователем функции:

Более короткий путь (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 (с Homebrew):

 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()); используйте подход старой школы: var_dump(debug_backtrace()); вместо dd() .

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

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

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

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

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

 $backtrace = debug_backtrace(); 

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

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

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

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

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

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

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

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