PHP Conference Japan 2024

debug_backtrace

(PHP 4 >= 4.3.0,PHP 5,PHP 7,PHP 8)

debug_backtrace產生回溯追蹤

描述

debug_backtrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT, int $limit = 0): array

debug_backtrace() 會產生 PHP 回溯追蹤。

參數

options

此參數是以下選項的位元遮罩

debug_backtrace() 選項
DEBUG_BACKTRACE_PROVIDE_OBJECT 是否填入 "object" 索引。
DEBUG_BACKTRACE_IGNORE_ARGS 是否省略 "args" 索引,因此省略所有函式/方法引數,以節省記憶體。

注意:

有四種可能的組合

debug_backtrace() 選項
debug_backtrace() 填入兩個索引
debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT)
debug_backtrace(1)
debug_backtrace(0) 省略 "object" 索引,並填入 "args" 索引。
debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) 省略 "object" 索引 "args" 索引。
debug_backtrace(2)
debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT|DEBUG_BACKTRACE_IGNORE_ARGS) 填入 "object" 索引省略 "args" 索引。
debug_backtrace(3)

limit

此參數可用於限制返回的堆疊框架數量。預設情況下 (limit=0) 會返回所有堆疊框架。

傳回值

傳回一個關聯式的 array 陣列。可能傳回的元素如下

來自 debug_backtrace() 的可能傳回元素
名稱 型別 描述
function string 目前的函式名稱。另請參閱 __FUNCTION__
line int 目前的行號。另請參閱 __LINE__
file string 目前的檔案名稱。另請參閱 __FILE__
class string 目前的 類別 名稱。另請參閱 __CLASS__
object object 目前的 物件
type string 目前的呼叫類型。如果是方法呼叫,則返回 "->"。如果是靜態方法呼叫,則返回 "::"。如果是函式呼叫,則不返回任何內容。
args array 如果在函式內,則會列出函式引數。如果在包含的檔案內,則會列出包含的檔案名稱。

範例

範例 #1 debug_backtrace() 範例

<?php
// 檔案名稱:/tmp/a.php

function a_test($str)
{
echo
"\n你好:$str";
var_dump(debug_backtrace());
}

a_test('朋友');
?>

<?php
// 檔案名稱:/tmp/b.php
include_once '/tmp/a.php';
?>

執行 /tmp/b.php 時,會產生類似以下的結果

Hi: friend
array(2) {
[0]=>
array(4) {
    ["file"] => string(10) "/tmp/a.php"
    ["line"] => int(10)
    ["function"] => string(6) "a_test"
    ["args"]=>
    array(1) {
      [0] => &string(6) "friend"
    }
}
[1]=>
array(4) {
    ["file"] => string(10) "/tmp/b.php"
    ["line"] => int(2)
    ["args"] =>
    array(1) {
      [0] => string(10) "/tmp/a.php"
    }
    ["function"] => string(12) "include_once"
  }
}

另請參閱

新增筆記

使用者貢獻的筆記 37 則筆記

jurchiks101 at gmail dot com
11 年前
這是我剛編寫的一個函式,用於取得清楚易懂的呼叫追蹤。它可能比其他一些替代方案更耗費資源,但它簡短、易於理解,並提供良好的輸出 (Exception->getTraceAsString())。

<?php
function generateCallTrace()
{
$e = new Exception();
$trace = explode("\n", $e->getTraceAsString());
// 反轉陣列,使步驟按時間順序排列
$trace = array_reverse($trace);
array_shift($trace); // 移除 {main}
array_pop($trace); // 移除對此方法的呼叫
$length = count($trace);
$result = array();

for (
$i = 0; $i < $length; $i++)
{
$result[] = ($i + 1) . ')' . substr($trace[$i], strpos($trace[$i], ' ')); // 將 '#someNum' 替換為 '$i)',設定正確的順序
}

return
"\t" . implode("\n\t", $result);
}
?>

範例輸出
1) /var/www/test/test.php(15): SomeClass->__construct()
2) /var/www/test/SomeClass.class.php(36): SomeClass->callSomething()
robert at medianis dot net
8 年前
關於 PHP 5.3.6 或更新版本的 debug_backtrace 選項的簡短說明

debug_backtrace() - 顯示所有選項
debug_backtrace(0) - 排除 ["object"]
debug_backtrace(1) - 與 debug_backtrace() 相同
debug_backtrace(2) - 排除 ["object"] 和 ["args"]

使用此範例,並嘗試使用不同的選項呼叫 debug_backtrace

<?php
function F1()
{
echo
"<br />";
echo
"in F1 now";
echo
"<pre>".print_r(debug_backtrace(2),true)."</pre>";
}

class
DebugOptionsTest
{
function
F2()
{
echo
"<br />";
echo
"in F2 now";
F1();
}

}

echo
"<hr />calling F1";
F1();

$c=new DebugOptionsTest();
echo
"<hr /><hr /><hr />calling F2";
$c->F2("testValue");

?>
jsnell at e-normous dot com
17 年前
如果您在錯誤處理常式中使用回溯追蹤函式,請避免在 args 上使用 var_export(),因為在某些情況下會導致嚴重錯誤,進而使您無法看到堆疊追蹤。某些結構會導致 PHP 產生嚴重錯誤「巢狀層級過深 - 遞迴相依性?」。這是 php 的設計特性,而不是錯誤(請參閱 http://bugs.php.net/bug.php?id=30471
liam at N0SPAM dot boxclever dot ca
1 年前
可以使用 ! 停用位元遮罩參數提供的選項。

<?php
debug_backtrace
( !DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS);
?>
Emmett Brosnan
8 年前
從 debug_backtrace 快速且粗略地格式化輸出。

$file_paths = debug_backtrace();

foreach($file_paths AS $file_path) {
foreach($file_path AS $key => $var) {
if($key == 'args') {
foreach($var AS $key_arg => $var_arg) {
echo $key_arg . ': ' . $var_arg . '<br>';
}
} else {
echo $key . ': ' . $var . '<br>';
}
}
}
michael dot schramm at gmail dot com
15 年前
如果您使用物件作為函式呼叫的引數,請小心!

<?php
error_reporting
(E_ALL);

function
myPrint($trace){
foreach(
$trace as $i=>$call){
/**
* 這是必要的!如果您的所有物件都有 __toString 函式,則不需要!
*
* 可捕獲的嚴重錯誤:無法將類別 B 的物件轉換為字串
* 可捕獲的嚴重錯誤:無法將類別 A 的物件轉換為字串
* 可捕獲的嚴重錯誤:無法將類別 B 的物件轉換為字串
*/
if (is_object($call['object'])) { $call['object'] = '已轉換類別 '.get_class($call['object']); }
if (
is_array($call['args'])) {
foreach (
$call['args'] AS &$arg) {
if (
is_object($arg)) { $arg = '已轉換類別 '.get_class($arg); }
}
}

$trace_text[$i] = "#".$i." ".$call['file'].'('.$call['line'].') ';
$trace_text[$i].= (!empty($call['object'])?$call['object'].$call['type']:'');
$trace_text[$i].= $call['function'].'('.implode(', ',$call['args']).')';
}

var_dump($trace_text);
}

class
A{
public function
test($obj){
$obj->test();
}
}

class
B{
public function
test(){
echo
myPrint(debug_backtrace());
}
}

$A = new A();
$B = new B();

$A->test($B);

?>
http://synergy8.com
18 年前
應注意,如果回溯追蹤中存在 call_user_func 之類的內部 php 函式,則不會設定 'file' 和 'line' 條目。

大多數偵錯追蹤器將會使用這些條目。您應在使用此函式之前檢查陣列中是否存在該鍵。否則將會產生通知。

<?php

$arrTrace
= debug_backtrace();

foreach (
$arrTrace as $arr)
{
if (!isset (
$arr['file']))
{
$arr['file'] = '[PHP 核心]';
}

if (!isset (
$arr['line']))
{
$arr['line'] = '';
}

// 執行某些操作
}

?>
root at jackyyf dot com
11 年前
當使用 register_shutdown_function 時,以及在關閉時呼叫的函式,則沒有關於此函式的行號或檔案名稱資訊,只提供函式、類別(如果有的話)、類型(如果有的話)和引數。
Bill Getas
13 年前
這是我的小小更新貢獻 - 它會以我偏好的方式列印彩色輸出。定義一個包含您的 IP 陣列的輔助函式 isRootIp();然後呼叫 bt() 只會回傳,因此您可以在不會有人知道的情況下在實際網站中加入回溯追蹤。

<?php
function bt()
{
if( !
isRootIp() )
{
return
false;
}
array_walk( debug_backtrace(), create_function( '$a,$b', 'print "<br /><b>". basename( $a[\'file\'] ). "</b> &nbsp; <font color=\"red\">{$a[\'line\']}</font> &nbsp; <font color=\"green\">{$a[\'function\']} ()</font> &nbsp; -- ". dirname( $a[\'file\'] ). "/";' ) );
}
?>
Anonymous
11 年前
簡單的函式,可取得 "檔案名稱:[類別->][函式(): ]" 格式的字串

<?php
function get_caller_info() {
$c = '';
$file = '';
$func = '';
$class = '';
$trace = debug_backtrace();
if (isset(
$trace[2])) {
$file = $trace[1]['file'];
$func = $trace[2]['function'];
if ((
substr($func, 0, 7) == 'include') || (substr($func, 0, 7) == 'require')) {
$func = '';
}
} else if (isset(
$trace[1])) {
$file = $trace[1]['file'];
$func = '';
}
if (isset(
$trace[3]['class'])) {
$class = $trace[3]['class'];
$func = $trace[3]['function'];
$file = $trace[2]['file'];
} else if (isset(
$trace[2]['class'])) {
$class = $trace[2]['class'];
$func = $trace[2]['function'];
$file = $trace[1]['file'];
}
if (
$file != '') $file = basename($file);
$c = $file . ": ";
$c .= ($class != '') ? ":" . $class . "->" : "";
$c .= ($func != '') ? $func . "(): " : "";
return(
$c);
}
?>

用法範例:

<?php
function debug($str) {
echo
get_caller_info() . $str . "<br>\n";
}
?>

get_caller_info() 將會回傳呼叫 debug() 的函式/類別->方法 的相關資訊。
jonas at faceways dot se
11 年前
當使用 debug_backtrace() 來檢查是否從其他呼叫者存取時,請記得要求 debug_backtrace 只需深入到所需的深度,並略過將整個除錯物件作為回傳參數。

<?php
if (count(debug_backtrace(FALSE, 1)) == 0)
{
// 執行某些操作
}
?>
anoam at yandex dot ru
10 年前
在不同的 PHP 版本中,資源的運作方式略有不同。

例如:
function foo($bar)
{
return debug_backtrace();
}

$resource = fopen(__FILE__, 'r');
$backtrace = foo($resource);
echo "當資源開啟時: " . gettype($backtrace[0]['args'][0]) . "\n";
fclose($resource);
echo "當資源關閉時: " . gettype($backtrace[0]['args'][0]) . "\n";

在 5.3.10 版本中,我得到
當資源開啟時: resource
當資源關閉時: resource

在 5.5.9 版本中
當資源開啟時: resource
當資源關閉時: unknown type

請小心。
d at rren dot me
12 年前
各位好,這裡只是一個提醒 - 結果陣列中的 ['args'] 資料是以參照方式提供的。我發現自己在不知情的情況下編輯了參照,如果你呼叫多次回溯,這將會在後續造成問題。

<?php
$trace
= array_reverse(debug_backtrace());

// 迴圈回溯
$la = 0;
$lb = count($trace);
while (
$la<$lb){

// 來自回溯的資料
$trace[$la]['file'];
$trace[$la]['line'];
$trace[$la]['args'];
$trace[$la]['function'];
// 來自回溯的資料

// 迴圈參數陣列
$ba = 0;
$bb = count($trace[$la]['args']);
while (
$ba<$bb){

$trace[$la]['args'][$ba] = "編輯一個參照/指標";

$ba++;
}
unset(
$bb);
unset(
$ba);
// 迴圈參數陣列

$la++;
}
unset(
$lb);
unset(
$la);
// 迴圈回溯
?>
kroczu AT interia DOT pl
17 年前
<?
// 實用且方便的除錯函式
// 它會顯示記憶體使用量和呼叫之間的時間流逝,因此我們可以快速找到需要最佳化的程式碼區塊...
// 範例結果
/*
debug example.php> 初始化
debug example.php> 程式碼行數: 39-41 時間: 2.0002 記憶體: 19 KB
debug example.php> 程式碼行數: 41-44 時間: 0.0000 記憶體: 19 KB
debug example.php> 程式碼行數: 44-51 時間: 0.6343 記憶體: 9117 KB
debug example.php> 程式碼行數: 51-53 時間: 0.1003 記憶體: 9117 KB
debug example.php> 程式碼行數: 53-55 時間: 0.0595 記憶體: 49 KB
*/

function debug()
{
static $start_time = NULL;
static $start_code_line = 0;

$call_info = array_shift( debug_backtrace() );
$code_line = $call_info['line'];
$file = array_pop( explode('/', $call_info['file']));

if( $start_time === NULL )
{
print "debug ".$file."> 初始化\n";
$start_time = time() + microtime();
$start_code_line = $code_line;
return 0;
}

printf("debug %s> 程式碼行數: %d-%d 時間: %.4f 記憶體: %d KB\n", $file, $start_code_line, $code_line, (time() + microtime() - $start_time), ceil( memory_get_usage()/1024));
$start_time = time() + microtime();
$start_code_line = $code_line;
}

////////////////////////////////////////////////
// 範例

debug();
sleep(2);
debug();
// 軟程式碼...
$a = 3 + 5;
debug();

// 硬程式碼
for( $i=0; $i<100000; $i++)
{
$dummy['alamakota'.$i] = 'alamakota'.$i;
}
debug();
usleep(100000);
debug();
unset($dummy);
debug();

?>
seaside dot ki at mac dot com
17 年前
我已經開始為 PHP 建立一個外部除錯伺服器。PHP 應用程式 require_once 一個 TADebugger(),它會與除錯伺服器通訊。在此處找到 OS X 通用二進制檔案 [包含 PHP 原始碼範例]

http://www.turingart.com/downloads/phpDebugger.zip

目前,TADebugger 允許將這些屬性發送到除錯伺服器

- 回溯呼叫
- 字串訊息
- 回溯呼叫所參考的原始碼檔案

請注意,該二進制檔案是早期版本。
admin at sgssweb dot com
18 年前
令人驚訝的是,debug_backtrace() 無法從用作函式第二個或後續引數的函式中取得引數。

<?php

function a($p) {
$backtrace = debug_backtrace();

if (isset(
$backtrace[0]['args']))
var_export($backtrace[0]['args']);
else
echo
"無法取得引數";
echo
"<br />";

return
$p;
}

function
b($p1, $p2, $p3) {
echo
"$p1, $p2, $p3";
}

// 這會輸出:
// array ( 0 => 'First a', )
// 無法取得引數
// 無法取得引數
// First a, Second a, Third a
b(a("First a"), a("Second a"), a("Third a"));

?>
kenorb at gmail dot com
14 年前
一行程式碼即可印出最簡單且最短的人類可讀的回溯追蹤:)
<?php
array_walk
(debug_backtrace(),create_function('$a,$b','print "{$a[\'function\']}()(".basename($a[\'file\']).":{$a[\'line\']}); ";'));
?>
jcmargentina at gmail dot com
5 年前
我想指出,新版本的 php 中的 debug_backtrace() 可以偵測遞迴 // 循環引用,避免記憶體消耗。

範例

<?php

class ParentClass {
public function
__construct()
{
$this->_child = new ChildClass($this);
var_dump(debug_backtrace());
}
}

class
ChildClass {
public function
__construct(ParentClass $p)
{
$this->_parent = $p;
}
}

$test = new ParentClass();
?>

輸出

array(1) {
[0]=>
array(7) {
["file"]=>
string(23) "/home/jcm/testdebug.php"
["line"]=>
int(18)
["function"]=>
string(11) "__construct"
["class"]=>
string(11) "ParentClass"
["object"]=>
object(ParentClass)#1 (1) {
["_child"]=>
object(ChildClass)#2 (1) {
["_parent"]=>
*遞迴*
}
}
["type"]=>
string(2) "->"
["args"]=>
array(0) {
}
}
}

注意 *遞迴* 提示
jake at qzdesign dot co dot uk
5 年前
`args` 元素僅包含實際傳遞給函式或方法的引數。它不包含未明確指定的預設參數。(至少,在 PHP 7.1.9 中是這樣。)這與 `func_get_args()` 的行為一致。
Anonymous
11 年前
一個常見的條目看起來像這樣
<?php
array(6) {
'file' =>
string(87) "DbSelector.php"
'line'
=>
int(171)
'function' =>
string(5) "error"
'class'
=>
string(42) "LoggingService"
'type'
=>
string(2) "::"
'args'
=>
array(
1) {
[
0] =>
string(27) "Connecting to DB: unittests"
}
}
?>

但請注意,「file」和「class」並不指向同一件事!
「file」指的是呼叫下一個步驟的檔案。
「class」是要呼叫的下一個步驟。

所以「file」是呼叫者,「class」是被呼叫者。
jlammertink at gmail dot com
14 年前
我使用這個簡單但有效的函式,以便可以看到子類別中哪個方法呼叫了父類別中的目前方法。

<?php
function get_caller_method()
{
$traces = debug_backtrace();

if (isset(
$traces[2]))
{
return
$traces[2]['function'];
}

return
null;
}
?>
nyoung55 at that_google_mail.com
11 年前
這是一個將 debug_backtrace 清晰地輸出到 error_log 的函式

<?php
/*
* 將回溯追蹤的輸出傳送到 error_log
* @param string $message 在回溯追蹤之前將傳送到 error_log 的可選訊息
*/
function log_trace($message = '') {
$trace = debug_backtrace();
if (
$message) {
error_log($message);
}
$caller = array_shift($trace);
$function_name = $caller['function'];
error_log(sprintf('%s: 從 %s:%s 呼叫', $function_name, $caller['file'], $caller['line']));
foreach (
$trace as $entry_id => $entry) {
$entry['file'] = $entry['file'] ? : '-';
$entry['line'] = $entry['line'] ? : '-';
if (empty(
$entry['class'])) {
error_log(sprintf('%s %3s. %s() %s:%s', $function_name, $entry_id + 1, $entry['function'], $entry['file'], $entry['line']));
} else {
error_log(sprintf('%s %3s. %s->%s() %s:%s', $function_name, $entry_id + 1, $entry['class'], $entry['function'], $entry['file'], $entry['line']));
}
}
}
?>
Gemorroj
11 年前
回溯追蹤的另一種格式變化。
參數 $ignore 用於忽略額外的呼叫。
<?php
/**
* 取得回溯追蹤 (backtrace)
*
* @param int $ignore 忽略的呼叫層級
*
* @return string
*/
protected function getBacktrace($ignore = 2)
{
$trace = '';
foreach (
debug_backtrace() as $k => $v) {
if (
$k < $ignore) {
continue;
}

array_walk($v['args'], function (&$item, $key) {
$item = var_export($item, true);
});

$trace .= '#' . ($k - $ignore) . ' ' . $v['file'] . '(' . $v['line'] . '): ' . (isset($v['class']) ? $v['class'] . '->' : '') . $v['function'] . '(' . implode(', ', $v['args']) . ')' . "\n";
}

return
$trace;
}
?>
kexianbin at diyism dot com
12 年前
在伺服器上不需要 Xdebug 或 dbg.so,回傳更詳細的訊息

diyism_trace.php
<?php
define
(TRACES_MODE, 'TEXTAREA');//'TEXTAREA' 或 'FIREPHP'
$GLOBALS['traces.pre']=array();
function
my_array_diff($arr1, $arr2)
{foreach (
$arr1 as $k=>$v)
{if (
in_array($v, $arr2, true))
{unset(
$arr1[$k]);
}
}
return
$arr1;
}
function
my_var_export($var, $is_str=false)
{
$rtn=preg_replace(array('/Array\s+\(/', '/\[(\d+)\] => (.*)\n/', '/\[([^\d].*)\] => (.*)\n/'), array('array (', '\1 => \'\2\''."\n", '\'\1\' => \'\2\''."\n"), substr(print_r($var, true), 0, -1));
$rtn=strtr($rtn, array("=> 'array ('"=>'=> array ('));
$rtn=strtr($rtn, array(")\n\n"=>")\n"));
$rtn=strtr($rtn, array("'\n"=>"',\n", ")\n"=>"),\n"));
$rtn=preg_replace(array('/\n +/e'), array('strtr(\'\0\', array(\' \'=>\' \'))'), $rtn);
$rtn=strtr($rtn, array(" Object',"=>" Object'<-"));
if (
$is_str)
{return
$rtn;
}
else
{echo
$rtn;
}
}
function
tick_handler()
{
$tmp=debug_backtrace();
$trace=my_array_diff($tmp, $GLOBALS['traces.pre']);
//echo '<pre>';var_export($trace);echo '</pre>';echo '<br/>'; //for debug diyism_trace.php
$trace=array_values($trace);
$GLOBALS['traces.pre']=$tmp;
if (
count($trace)>0 && $trace[0]['file'].'/'.@$tmp[1]['function']!==@$GLOBALS['traces'][count($GLOBALS['traces'])-1]['key']) //過濾空陣列並重新排列 array_values(),因為某些行會觸發每行兩個 tick 事件,例如:1.最後一行是 "some code;questmark>" 2.error_reporting(...
{for ($i=count($trace)-1; $i>=0; --$i)
{
$GLOBALS['traces'][]=$tmp_fb=array_merge(array('key'=>$trace[$i]['file'].'/'.@$tmp[$i+1]['function']), $trace[$i], array('function'=>strtr($trace[$i]['function'], array('tick_handler'=>'CONTINUE')), 'in_function'=>@$tmp[$i+1]['function']));
TRACES_MODE==='FIREPHP'?fb(trace_output($tmp_fb), 'diyism_trace:'.++$GLOBALS['diyism_trace_no']):'';
}
}
}
function
trace_output($trace)
{
$trace['in_function']=strtr(@$trace['in_function'], array('require'=>'', 'require_once'=>'', 'include'=>'', 'include_once'=>''));
$trace['args']=$trace['args']?strtr(preg_replace(array('/\n +/'), array(''), preg_replace(array('/\n \d+ => /'), array(''), substr(my_var_export($trace['args'], true), 7, -3))), array("\r"=>'\r', "\n"=>'\n')):'';
return
$trace['file'].($trace['in_function']?'/'.$trace['in_function'].'()':'').'/'.$trace['line'].': '.$trace['function'].'('.$trace['args'].')';
}
function
traces_output()
{echo
'<textarea style="width:100%;height:300px;">';
$GLOBALS['traces']=array_slice($GLOBALS['traces'], 2);//移除註冊 tick 行和要求 'diyism_trace.php' 行
foreach ($GLOBALS['traces'] as $k=>$trace)
{echo
htmlentities($k.':'.trace_output($trace)."\n");
}
echo
'</textarea>';
}
register_tick_function('tick_handler');
TRACES_MODE==='TEXTAREA'?register_shutdown_function('traces_output'):'';
?>

test.php
<?php
declare(ticks=1);
require
'diyism_trace.php';

a('a', array('hello'));
1+2;
b();
function
a()
{
$d=1;
b();
$d=2;
}
function
b()
{
1+1;
}
?>
php noob
14 年前
令人驚訝的是,竟然沒有人描述過這個功能的最佳用途之一:傾印變數並顯示其位置。當進行除錯時,尤其是在大型且不熟悉的系統中,要記住我在哪裡添加了這些變數傾印是很麻煩的。此外,這種方式還能在多個傾印呼叫之間產生分隔符號。

<?php

function dump( $var ) {
$result = var_export( $var, true );
$loc = whereCalled();
return
"\n<pre>Dump: $loc\n$result</pre>";
}

function
whereCalled( $level = 1 ) {
$trace = debug_backtrace();
$file = $trace[$level]['file'];
$line = $trace[$level]['line'];
$object = $trace[$level]['object'];
if (
is_object($object)) { $object = get_class($object); }

return
"Where called: line $line of $object \n(in $file)";
}
?>

此外,從任何函式呼叫 'whereCalled()' 將快速識別出正在執行意外操作的位置(例如,在錯誤的時間更新屬性)。我剛接觸 PHP,但多年來一直在 Perl 中使用等效的功能。
php at kennel17 dot co dot uk
17 年前
在我的上一則筆記中,陣列的 'object' 元素可以用來取得父物件。因此,將 get_class_static() 函式變更為以下內容將使程式碼如預期般運作

<?php
function get_class_static() {
$bt = debug_backtrace();

if (isset(
$bt[1]['object']))
return
get_class($bt[1]['object']);
else
return
$bt[1]['class'];
}
?>

但是,當靜態呼叫時仍然會失敗。將我先前範例的最後兩行變更為

<?php
foo
::printClassName();
bar::printClassName();
?>

...在 PHP5 中仍然會產生相同的問題結果,但在這種情況下,'object' 屬性未設定,因此該技術不可用。
john dot risken at gmail dot com
14 年前
每個人似乎都有他們最喜歡的用法。我用這個函式取代 die()。它會給使用者一個訊息
並將錯誤的 PrettyPrint 版本以電子郵件寄給我。$info 由我設定,
並在資料庫物件中執行特殊檢查。

<?php
// var_format

function var_format($v) // pretty-print var_export
{
return (
str_replace(array("\n"," ","array"),
array(
"<br>","&nbsp;","&nbsp;<i>array</i>"),
var_export($v,true))."<br>");
}
function
myDie($info)
{
$mysqlerr=strpos($info,"ERROR=You have an error in your SQL syntax");
if(
$mysqlerr>0)$info=substr($info,0,$mysqlerr)." mySql format error";
$out="<br>MSG='$info'<br>".var_format($_REQUEST)."<br>";
$bt=debug_backtrace();
$sp=0;
$trace="";
foreach(
$bt as $k=>$v)
{
extract($v);
$file=substr($file,1+strrpos($file,"/"));
if(
$file=="db.php")continue; // the db object
$trace.=str_repeat("&nbsp;",++$sp); //spaces(++$sp);
$trace.="file=$file, line=$line, function=$function<br>";
}
$out.="<br>".backTrace();
if(
substr($info,0,4)=="XXX ") // special errrors when db is inaccessible
{
$out=str_replace("<br>","\n",$out);
$out=str_replace("&nbsp;"," ",$out);
mail("me@example.com","Database Execution Error for user ".$REMOTE_ADDR,"$out");
exit(
"Database Access Error. Please try again later.");
}
mail("me@example.com",'Error Monitor','Execution Error',$out);
exit(
"DANG! An execution error in the program has been sent to the webmaster.
If you don't get an email from him soon, please call him."
);
}
?>

這會產生如下的輸出

file=badmode.php, line=5, function=backTrace
file=login.php, line=209, function=require
file=midScreen.php, line=264, function=require
file=masterindex.php, line=161, function=require
file=production2.php, line=121, function=require
file=index.php, line=16, function=require
frank at frank dot com
16 年前
這是我的簡單範例
程式碼列印了實例化列印類別的類別的變數。

嗯,我相信您在看過程式碼後就會明白
列印結果是:jippii

<?php
class A {

function
something() {
$s = debug_backtrace();

$callingObject = $s[1]['object'];
$test = $callingObject->jip;
print
$test;
}

}

class
B {
var
$jip;

function
execute() {
$a = new A();
$this->jip = "jippii";
$a->something();
}

}
$control = new B();
$control->execute();
?>
samthor
16 年前
這裡有一種方法可以在堆疊中取得上游函式的引數(適用於類別方法、靜態方法和非類別方法)
<?php
/**
* getArgs - 尋找上層方法 (upstream method) 的參數
* 可以使用例如 "funcname", "class::staticmethod", "class->instancemethod" 的方式呼叫。
*/
function getArgs( $target, $subclass_ok = true ) {

if(
strpos( $target, "::" ) ) {
list(
$class, $target ) = explode( "::", $target, 2 );
$type = "::";
}
else if(
strpos( $target, "->" ) ) {
list(
$class, $target ) = explode( "->", $target, 2 );
$type = "->";
}
else {
$type = NULL;
$class = NULL;
}
$class and $class = new ReflectionClass( $class );

foreach(
debug_backtrace() as $obj ) {

if(
$obj['function'] == $target ) {
if(
$type and $obj['type'] == $type ) {
$_cl = new ReflectionClass( $obj['class'] );
if(
$_cl->getName() == $class->getName() or ( $subclass_ok and $_cl->isSubclassOf( $class ) ) ) {
return
$obj['args'];
}
unset(
$_cl );
}
else if( !
$type ) {
return
$obj['args'];
}
}

}

return
NULL;

}
?>

一些範例用法
<?php
class Foo {
function
test() {
$args = getArgs( "Foo->base" );
print(
"我呼叫 base 時的參數 'v' 是: {$args[0]}\n" );
}
function
base( $v ) {
$this->test();
}
}

$f = new Foo();
$f->base( 713 ); // 會印出:".. 我呼叫 base 時的參數 'v' 是: 713"

?>

相信我,你會想要這樣做的原因是有一些的 :)
bernyregeling AT hotmail DOT com
21 年前
我除了 jlim 之外,還寫了這個函數,用於漂亮的非 HTML 輸出。

結果類似於 Java 錯誤。希望你喜歡。

(順便說一下,如果顯示 debug_backtrace,此函數也會結束腳本)
------------------------------
function debug_bt()
{
if(!function_exists('debug_backtrace'))
{
echo 'function debug_backtrace does not exists'."\r\n";
return;
}
//echo '<pre>';
echo "\r\n".'----------------'."\r\n";
echo 'Debug backtrace:'."\r\n";
echo '----------------'."\r\n";
foreach(debug_backtrace() as $t)
{
echo "\t" . '@ ';
if(isset($t['file'])) echo basename($t['file']) . ':' . $t['line'];
else
{
// 如果沒有設定檔案,我假設函數呼叫
// 來自 PHP 編譯的原始碼 (例如 XML 回呼)。
echo '<PHP inner-code>';
}

echo ' -- ';

if(isset($t['class'])) echo $t['class'] . $t['type'];

echo $t['function'];

if(isset($t['args']) && sizeof($t['args']) > 0) echo '(...)';
else echo '()';

echo "\r\n";
}
//echo '</pre>';
exit;
}
icefragment at gmail dot com
18 年前
一個簡單的類似 Python 的回溯追蹤。請注意,如果陣列作為函數的參數傳遞,我不會遞迴進入陣列。

function backtrace()
{
$bt = debug_backtrace();

echo("<br /><br />回溯追蹤 (最近的呼叫在最後):<br /><br />\n");
for($i = 0; $i <= count($bt) - 1; $i++)
{
if(!isset($bt[$i]["file"]))
echo("[PHP 核心呼叫的函數]<br />");
else
echo("檔案:".$bt[$i]["file"]."<br />");

if(isset($bt[$i]["line"]))
echo("&nbsp;&nbsp;&nbsp;&nbsp;行號 ".$bt[$i]["line"]."<br />");
echo("&nbsp;&nbsp;&nbsp;&nbsp;呼叫的函數:".$bt[$i]["function"]);

if($bt[$i]["args"])
{
echo("<br />&nbsp;&nbsp;&nbsp;&nbsp;參數: ");
for($j = 0; $j <= count($bt[$i]["args"]) - 1; $j++)
{
if(is_array($bt[$i]["args"][$j]))
{
print_r($bt[$i]["args"][$j]);
}
else
echo($bt[$i]["args"][$j]);

if($j != count($bt[$i]["args"]) - 1)
echo(", ");
}
}
echo("<br /><br />");
}
}
zmorris at mac dot com
18 年前
嗨,我厭倦了使用我製作的 trace( $message, __FILE__, __LINE__ ) 函數。它強迫我包含檔案和行參數 (因為 php 沒有巨集),所以我決定製作一個替代方案。

只需使用 trace( '我的訊息' ); 呼叫這個新版本,它會以比儲存在 debug_backtrace() 陣列中更清晰的方式印出堆疊追蹤。它可以處理函數外部的追蹤、巢狀函數中的追蹤以及包含的檔案中的追蹤,並以可以貼回您的 php 程式碼中以進行更快測試的方式顯示函數!

注意 - 請務必使用正確的行尾符儲存您的檔案,以便行號可以正確運作,而對於 Mac OS X 來說是 unix。您可以在 BBEdit 中每個視窗頂部的工具列中的快顯選單中找到此選項。

<?php

function print_var( $var )
{
if(
is_string( $var ) )
return(
'"'.str_replace( array("\x00", "\x0a", "\x0d", "\x1a", "\x09"), array('\0', '\n', '\r', '\Z', '\t'), $var ).'"' );
else if(
is_bool( $var ) )
{
if(
$var )
return(
'true' );
else
return(
'false' );
}
else if(
is_array( $var ) )
{
$result = 'array( ';
$comma = '';
foreach(
$var as $key => $val )
{
$result .= $comma.print_var( $key ).' => '.print_var( $val );
$comma = ', ';
}
$result .= ' )';
return(
$result );
}

return(
var_export( $var, true ) ); // anything else, just let php try to print it
}

function
trace( $msg )
{
echo
"<pre>\n";

//var_export( debug_backtrace() ); echo "</pre>\n"; return; // this line shows what is going on underneath

$trace = array_reverse( debug_backtrace() );
$indent = '';
$func = '';

echo
$msg."\n";

foreach(
$trace as $val)
{
echo
$indent.$val['file'].' on line '.$val['line'];

if(
$func ) echo ' in function '.$func;

if(
$val['function'] == 'include' ||
$val['function'] == 'require' ||
$val['function'] == 'include_once' ||
$val['function'] == 'require_once' )
$func = '';
else
{
$func = $val['function'].'(';

if( isset(
$val['args'][0] ) )
{
$func .= ' ';
$comma = '';
foreach(
$val['args'] as $val )
{
$func .= $comma.print_var( $val );
$comma = ', ';
}
$func .= ' ';
}

$func .= ')';
}

echo
"\n";

$indent .= "\t";
}

echo
"</pre>\n";
}

trace( 'error outside function' );

function
test( $param1, $param2, $param3, $param4 )
{
trace( 'error in test()' );
}

test( 1.1, "param2\n", array( 1 => "a\n", "b\n" => 2 ), false );

?>
jlim#natsoft.com.my
21 年前
美化 backtrace() 的輸出。函式會根據呼叫值縮排,並為了方便起見使用 file:// 連結檔案。

盡情享用,John Lim

function adodb_backtrace($print=true)
{
$s = '';
if (PHPVERSION() >= 4.3) {

$MAXSTRLEN = 64;

$s = '<pre align=left>';
$traceArr = debug_backtrace();
array_shift($traceArr);
$tabs = sizeof($traceArr)-1;
foreach ($traceArr as $arr) {
for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';
$tabs -= 1;
$s .= '<font face="Courier New,Courier">';
if (isset($arr['class'])) $s .= $arr['class'].'.';
foreach($arr['args'] as $v) {
if (is_null($v)) $args[] = 'null';
else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
else if (is_object($v)) $args[] = 'Object:'.get_class($v);
else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
else {
$v = (string) @$v;
$str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
if (strlen($v) > $MAXSTRLEN) $str .= '...';
$args[] = $str;
}
}

$s .= $arr['function'].'('.implode(', ',$args).')';
$s .= sprintf("</font><font color=#808080 size=-1> # 行 %4d,".
" 檔案:<a href=\"file:/%s\">%s</a></font>",
$arr['line'],$arr['file'],$arr['file']);
$s .= "\n";
}
$s .= '</pre>';
if ($print) print $s;
}
return $s;
}
spagmoid at yahoo dot NOSPAMcom
20 年前
致:jlim#natsoft.com.my

很棒的函式,但您有一些錯誤。

在這一行
foreach($arr['args'] as $v)

將其變更為
$args = array();
if(!empty($arr['args'])) foreach($arr['args'] as $v)

由於從錯誤處理常式呼叫時,陣列中不存在行和檔案,

$Line = (isset($arr['line'])? $arr['line'] : "unknown");
$File = (isset($arr['file'])? $arr['file'] : "unknown");

並相應地替換。

這是我的版本,可惜格式不同
----------------------------------------

function DBG_GetBacktrace()
{
$s = '';
$MAXSTRLEN = 64;

$s = '<pre align=left>';
$traceArr = debug_backtrace();
array_shift($traceArr);
$tabs = sizeof($traceArr)-1;
foreach($traceArr as $arr)
{
for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';
$tabs -= 1;
$s .= '<font face="Courier New,Courier">';
if (isset($arr['class'])) $s .= $arr['class'].'.';
$args = array();
if(!empty($arr['args'])) foreach($arr['args'] as $v)
{
if (is_null($v)) $args[] = 'null';
else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
else if (is_object($v)) $args[] = 'Object:'.get_class($v);
else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
else
{
$v = (string) @$v;
$str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
if (strlen($v) > $MAXSTRLEN) $str .= '...';
$args[] = "\"".$str."\"";
}
}
$s .= $arr['function'].'('.implode(', ',$args).')</font>';
$Line = (isset($arr['line'])? $arr['line'] : "unknown");
$File = (isset($arr['file'])? $arr['file'] : "unknown");
$s .= sprintf("<font color=#808080 size=-1> # 行 %4d, 檔案:<a href=\"file:/%s\">%s</a></font>",
$Line, $File, $File);
$s .= "\n";
}
$s .= '</pre>';
return $s;
}
henzeberkheij at gmail dot com
14 年前
我發現知道函式是否正在被呼叫很有用。例如,在 Java 中,您通常會在函式開頭列印一行包含函式名稱和引數的程式碼。我希望在 php 中實現相同的目標,因此我編寫了以下類別

<?php
class Debug
{
private static
$calls;

public static function
log($message = null)
{
if(!
is_array(self::$calls))
self::$calls = array();

$call = debug_backtrace(false);
$call = (isset($call[1]))?$call[1]:$call[0];

$call['message'] = $message;
array_push(self::$calls, $call);
}
}
?>

在其他任何程式碼之前包含此類別
用法:在您的函式開頭使用 Debug::log($message);。

為自己編寫一份漂亮的資料列印輸出;
ciprian dot stingu at gmail dot com
13 年前
我用於偵錯的函式
我縮短了變數名稱,並刪除了第二個函式中的空格,以便放入貼文中 :(

<?php
define
("LFP", './lt.log');
function
LogTrace($Argument, $lfn = LFP, $itw = ' ')
{
error_log("=====\r", 3, $lfn);
error_log("[BEGIN BACKTRACE]\r", 3, $lfn);
$it = '';
$Ts = array_reverse(debug_backtrace());
foreach(
$Ts as $T)
{
if(
$T['function'] != 'include' && $T['function'] != 'require' && $T['function'] != 'include_once' && $T['function'] != 'require_once')
{
$ft = $it . '<'. basename($T['file']) . '> on line ' . $T['line'];
if(
$T['function'] != 'LogTrace')
{
if(isset(
$T['class']))
$ft .= ' in method ' . $T['class'] . $T['type'];
else
$ft .= ' in function ';
$ft .= $Trace['function'] . '(';
}
else
$ft .= '(';
if(isset(
$T['args'][0]))
{
if(
$T['function'] != 'LogTrace')
{
$ct = '';
foreach(
$T['args'] as $A)
{
$ft .= $ct . LogVar($A, '', $it, $itw, 0);
$ct = $it . $itw . ',';
}
}
else
$ft .= LogVar($T['args'][0], '', $it, $itw, 0);
}
$ft .= $it . ")\r";
error_log($ft, 3, $lfn);
$it .= $itw;
}
}
error_log("[END BACKTRACE]\r", 3, $lfn);
}

function
LogVar(&$Var, $vn, $pit, $itw, $nlvl, $m = '')
{
if(
$nlvl>=16) return;
if(
$nlvl==0){$tv=serialize($Var);$tv=unserialize($tv);}
else
$tv=&$Var;
$it=$pit.$itw;
for(
$i=0; $i<$nlvl;$i++) $it.='.'.$itw;
$o='';$nl="\n";
if(
is_array($tv))
{
if(
strlen($vn)>0) $o.=$it.$m.'<array> $'.$vn.' = (';
else
$o.="\r".$it.$m.'<array> = (';
$o.= $nl;$AK=array_keys($tv);
foreach(
$AK as $AN) {$AV=&$tv[$AN];$o.=LogVar($AV,$AN,$pit,$itw,$nlvl+1);}
$o.=$it.')'.$nl;
}
else if(
is_string($tv))
{
if(
strlen($vn)>0)$o.=$it.$m.'<string> $'.$vn.' = ';
else
$o.=' '.$m.'<string> = ';
if(
$tv===null) $o.='NULL';
else
$o.='"'.$tv.'"';
$o.=$nl;
}
else if(
is_bool($tv))
{
if(
strlen($vn) > 0) $o.=$it.$m.'<boolean> $'.$vn.' = ';
else
$o.=' '.$m.'<boolean> = ';
if(
$tv===true) $o.='TRUE';
else
$o.='FALSE';
$o.=$nl;
}
else if(
is_object($tv))
{
if(
strlen($vn)>0)
{
$o.=$pit.$itw;
for(
$i=0;$i<$nlvl;$i++) $o.='.'.$itw;
$o.=$m.'<'.get_class($tv).'::$'.$vn.'> = {'.$nl;
}
else
$o.=' '.$m.'<'.get_class($tv).'::> = {'.$nl;
$R=new ReflectionClass($tv);
$o.=$it.'.'.$itw.'Class methods {'.$nl;
$CM=$R->getMethods();
foreach(
$CM as $MN => $MV)
{
$o.=$it.'.'.$itw.'.'.$itw.implode(' ',Reflection::getModifierNames($MV->getModifiers())).' '.$MV->getName().'(';
$MP=$MV->getParameters(); $ct='';
foreach(
$MP as $MPN => $MPV)
{
$o.=$ct; $o.=$MPV->isOptional()?'[':'';
if(
$MPV->isArray()) $o.='<array> ';
else if(
$MPV->getClass()!==null) $o.='<'.$MPV->getClass()->getName().'::> ';
$o.=$MPV->isPassedByReference()?'&':''; $o.='$'.$MPV->getName();
if(
$MPV->isDefaultValueAvailable())
{
if(
$MPV->getDefaultValue()===null) $o.=' = NULL';
else if(
$MPV->getDefaultValue()===true) $o.=' = TRUE';
else if(
$MPV->getDefaultValue()===false) $o.=' = FALSE';
else
$o.=' = '.$MPV->getDefaultValue();
}
$o.=$MPV->isOptional()?']':''; $ct=', ';
}
$o.=')'.$nl;
}
$o.=$it.'.'.$itw.'}'.$nl; $o.=$it.'.'.$itw.'Class properties {'.$nl;
$CV=$R->getProperties();
foreach(
$CV as $CN => $CV)
{
$M=implode(' ',Reflection::getModifierNames($CV->getModifiers())).' ';
$CV->setAccessible(true);
$o.=LogVar($CV->getValue($tv),$CV->getName(),$pit,$itw,$nlvl+2,$M);
}
$o.=$it.'.'.$itw.'}'.$nl; $o.=$it.'.'.$itw.'Object variables {'.$nl;
$OVs=get_object_vars($tv);
foreach(
$OVs as $ON => $OV) $o.=LogVar($OV,$ON,$pit,$itw,$nlvl+2);
$o.=$it.'.'.$itw.'}'.$nl; $o.=$pit.$itw;
for(
$i=0;$i<$nlvl;$i++) $o.='.'.$itw;
$o.='}'.$nl;
}
else
{
if(
strlen($vn)>0) $o.=$it.$m.'<'.gettype($tv).'> $'.$vn.' = '.$tv;
else
$o.=' '.$m.'<'.gettype($tv).'> = '.$tv;
$o.=$nl;
}
return
$o;
}
//test
date_default_timezone_set('Europe/Bucharest');
$date = new DateTime('2010-01-28');
LogTrace($date);
?>
aryel at iku dot com dot br
16 年前
一個簡單的函式,可擷取偵錯回溯的所有詳細資訊

<?php
function getDebugBacktrace($NL = "<BR>") {
$dbgTrace = debug_backtrace();
$dbgMsg .= $NL."Debug backtrace begin:$NL";
foreach(
$dbgTrace as $dbgIndex => $dbgInfo) {
$dbgMsg .= "\t at $dbgIndex ".$dbgInfo['file']." (line {$dbgInfo['line']}) -> {$dbgInfo['function']}(".join(",",$dbgInfo['args'])")$NL";
}
$dbgMsg .= "Debug backtrace end".$NL;
return
$dbgMsg;
}
?>

接著,您可以在任何您想取得易讀格式的除錯回溯字串的地方呼叫它(例如,您的錯誤處理函式)。

<?php
$backtrace
= getDebugBacktrace();
echo
"Fatal error! Cannot connect to database!";
echo
$backtrace;
?>

如果您在命令列上執行,您可能需要替換行分割符號。您可以使用函式參數來實現。

<?php
$backtrace
= getDebugBacktrace("\n");
echo
"Error! Server is running out of foos! Dumping error backtrace";
echo
$backtrace;
?>

希望這有幫助,
Aryel
To Top