デフォルトの現在の行のみのエラーメッセージを使用してPHPをデバッグしようとすると、ひどいことになります。エラーが発生したときにPHPにバックトレース(スタックトレース)を生成させるにはどうすればよいですか?
12 に答える
バックトレースを生成するエラーハンドラーをインストールするための私のスクリプト:
<?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()
です。そのため、これらのエラーでは、最終的な場所のみのエラーが発生します。
Xdebugはエラーのバックトレーステーブルを出力し、それを実装するためにPHPコードを記述する必要はありません。
欠点は、PHP拡張機能としてインストールする必要があることです。
PHPエラー
これは、PHPで記述されたPHPのエラー報告に適しています。追加の拡張機能は必要ありません!
通常のAJAXyリクエスト(一時停止状態)の場合、ブラウザにすべてのエラーが表示される場所を使用するのは簡単です。次に、すべてのエラーにより、関数の引数、サーバー変数を含む、スタックトレース全体にわたるバックトレースとコードコンテキストが提供されます。
あなたがする必要があるのは、1つのファイルを含めて関数を呼び出すことです(コードの最初に)、例えば
require('php_error.php');
\php_error\reportErrors();
スクリーンショットを参照してください。
GitHub:https ://github.com/JosephLenton/PHP-エラー
私のフォーク(追加の修正あり):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
注:一度に発生できるエラー例外は1つだけです。set_error_handler()関数を呼び出すと、古いエラーハンドラーの名前が返されます。これを保存して、エラーハンドラから自分で呼び出すことができます。したがって、複数のエラーハンドラを使用できます。
XDebug
より高度なソリューションについては、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の場合(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'
。
Develを有効にしない場合は、var_dump(debug_backtrace());
の代わりに古い学校のアプローチを使用してdd()
ください。
問題のある行にdebug_backtrace()の内容を含むセッション変数を設定し、register_shutdown_function()を使用して出力してみました。チャームのように働いた。
debug_backtraceを使用できます
これがあなたのやり方です:
set_error_handler(function($errorType){
if(error_reporting() & $errorType){
?><pre><?
debug_print_backtrace();
?></pre><?
}
}) ;
クロージャを使用するため、PHP5.3以降が必要です。より低いPHPサポートが必要な場合は、クロージャーを通常の関数に変換するだけです。
$backtrace = debug_backtrace();
しばらく前にバックトレースについての小さな記事を書きました
set_error_handler()
++ debug_backtrace()
PHP5debug_print_backtrace()
では
デバッガーをインストールできない場合は、この関数を使用して致命的なエラーを回避し、「致命的なスタック」を取得します。以下のコードと例を確認して、使用方法を詳しく説明します。
// 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
}
}
また、バックトレースの内部スタックの場合、一部のキーが設定されないことに注意してください。すべてのエラーがある場合は、キーを使用する前に、必ずキーが存在するかどうかを確認してください:)
(new \Exception())->getTraceAsString()
代わりに使用できますdebug_backtrace()
:
set_error_handler(function(int $severity, string $message, string $file, int $line) {
if (!(error_reporting() & $severity)) {
return false;
}
$severities = [
E_ERROR => 'ERROR',
E_WARNING => 'WARNING',
E_PARSE => 'PARSE',
E_NOTICE => 'NOTICE',
E_CORE_ERROR => 'CORE_ERROR',
E_CORE_WARNING => 'CORE_WARNING',
E_COMPILE_ERROR => 'COMPILE_ERROR',
E_COMPILE_WARNING => 'COMPILE_WARNING',
E_USER_ERROR => 'USER_ERROR',
E_USER_WARNING => 'USER_WARNING',
E_USER_NOTICE => 'USER_NOTICE',
E_STRICT => 'STRICT',
E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
E_DEPRECATED => 'DEPRECATED',
E_USER_DEPRECATED => 'USER_DEPRECATED',
];
$e = new \Exception;
// Just remove the current point from the trace
$reflection = new \ReflectionProperty(get_class($e), 'trace');
$reflection->setAccessible(true);
$trace = $reflection->getValue($e);
array_shift($trace);
$reflection->setValue($e, $trace);
$text = '';
$text .= ($severities[$severity] ?? $severity) . ': ';
$text .= "$message in $file($line)\n";
$text .= "Stack trace:\n";
$text .= $e->getTraceAsString();
error_log($text);
if (in_array($severity, [
E_CORE_ERROR,
E_ERROR,
E_RECOVERABLE_ERROR,
E_PARSE,
E_COMPILE_ERROR,
E_USER_ERROR,
], true)) {
http_response_code(500);
exit(255);
}
return true;
});
出力:
[16-Feb-2022 00:01:09 UTC] DEPRECATED: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /home/user/project/doSomething.php(3)
Stack trace:
#0 /home/user/project/doSomething.php(3): trim(NULL)
#1 /home/user/project/index.php(4): doSomething()
#2 {main}