我也使用 debug_backtrace,我尝试处理不同的场景,这可能看起来太耗时或坏主意,但对我来说(构建我自己的小型 mvc 非常有帮助)。要处理的场景示例:
- 退出调用者上下文时自动调用我的类的__destruct
- 我的类的方法/析构被自动调用,因为被声明为会话处理程序
- 我的方法/函数是从全局上下文调用的(而不是从其他函数/方法)
- 等等..
所有这些场景都会影响 debug_backtrace 带来的结果,我的调试函数(定义如下)试图处理这些场景。
每个函数/方法都是这样定义的
function my_func(){if(__DEBUG){dbg(debug_backtrace(),__CLASS__);}
然后,当我想生成最终代码时,我可以运行一个简单的脚本来替换该 if 语句,例如
a="if(__DEBUG){dbg(debug_backtrace(),__CLASS__);}"
b="//replace_what_ever"
dir="/var/www/mydir/"
find $dir -name \*.inc -exec sed -i "s/$a/$b/g" {} \;
find $dir -name \*.php -exec sed -i "s/$a/$b/g" {} \;
至于调试功能,它可以在脚本的最后执行,比如说在 index.php 的最后。但是,如果您为会话处理程序定义了一个自己的类,那么最后一个命令将在内部执行该类的析构函数。
因此,在大多数情况下,当出现问题时,您的调试功能会通知您。但是,如果出现致命错误,打印调试函数创建/存储的结果(存储在某个数组中,这里是 $dbg_log)的行将无法打印(例如,打印命令放在 index.php 的末尾)!!对于这种情况,您需要一个手动处理程序(仅适用于致命错误)来打印结果数组,这就是我的做法:
register_shutdown_function('handleShutdown');
//Catch fatal errors
function handleShutdown() {
$error = error_get_last();
global $dbg_log;
echo "<pre>";
if(
$error['type'] === E_COMPILE_ERROR or
$error['type'] === E_ERROR or
$error['type'] === E_PARSE or
$error['type'] === E_CORE_ERROR or
$error['type'] === E_CORE_WARNING or
$error['type'] === E_RECOVERABLE_ERROR
)//we need to catch fatal errors under debug
{
//print_r($error); if you like
$dbg_log[] = " Tip: Start backward, the failing function (line) cannot echo a text put at the end of the function!";
$last = count($dbg_log)-1;
for($i=$last;$i>-1;$i--){
echo "$i: {$dbg_log[$i]} \n<br>";
}
}
}
$dbg_log 用于收集在全局上下文中定义的所有这些信息(见下文)。
现在这是我的调试功能的样子:
define('__DEBUG', true); // Easily switch from/to debug mode
$dbg_log = array(); // Keep log of function calling sequence for debuging purposes
function dbg($tr, $callee_class){
global $dbg_log;
// If the file of the caller exists
if(isset($tr[0]['file'])){
$caller = $caller=$tr[0]["file"].':'.$tr[0]["line"]; // Then we can get its name and calling line
// If the caller is a function then it was a callee before so $tr[1] should exists
if(isset($tr[1])){
// If the caller is a class method
if(isset($tr[1]["class"])){
$caller = $tr[1]["class"]."whenever->".$caller=$tr[1]["function"].':'.$caller;
}
// Else
else{
$caller = $tr[1]["function"].$caller;
}
}
}
// Else this is an auto call by php compiler
else{
$caller = 'auto';
}
// Log the debug info
$dbg_log[] = 'Started: '.$callee_class.'::'.$tr[0]['function'].' by '.$caller;
}
$tr (trace) 数组包含 debug_backtrace 的结果,因为它们存在于被调用函数中。另一件事要提到的是,在成为呼叫者之前,呼叫者始终是被呼叫者!
这些是 $dbg_log 数组的输出给出的一些真实的(对你来说毫无意义,但是提供的全部信息是显而易见的)结果(在致命错误或正常退出时):
27: Started: Framework\registry::get by App\View\WebWindowOne->__construct:/var/www/MyProject/protected/view/WebWindowOne/WebWindowOne.php:36
26: Started: App\View\WebWindowOne::__construct by Application->AppStart:/var/www/MyProject/protected/Web_Application.php:240
25: Started: Application::AppStart by Application->__construct:/var/www/MyProject/protected/Web_Application.php:150
24: Started: Framework\riskManager::__construct by Application->{closure}:/var/www/MyProject/protected/Web_Application.php:52
您定义的每个函数/方法都包含大量信息、行号、类等,只需很少的努力(只需使用此function my_func(){if(__DEBUG){dbg(debug_backtrace(),__CLASS__);})。