對於大部分編譯型語言來說,例如C 、 Java 、 C# ,我們都能很方便地進行斷點調試,但是PHP 則必須安裝XDebug 並且在編輯器中進行複雜的配置才能實現斷點偵錯的能力。
不過,如果只是簡單的調試並且查看堆疊回溯的話,其實 PHP 已經為我們準備好了兩個函數,能夠讓我們非常方便的看到程式運行時的呼叫情況。
debug_backtrace()
從這個方法的字面意思就可以看出,它的意思就是偵錯回溯,傳回的也正是一段回溯訊息的陣列。
function a_test($str) { echo "Hi: $str", PHP_EOL; var_dump(debug_backtrace()); } var_dump(debug_backtrace()); a_test("A"); // Hi: A/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php:7: // array(1) { // [0] => // array(4) { // 'file' => // string(93) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php" // 'line' => // int(12) // 'function' => // string(6) "a_test" // 'args' => // array(1) { // [0] => // string(1) "A" // } // } // }
這個方法必須在函數中調用,在函數方法外部使用是不會有內容的。從內容看,它輸出了關於這個函數的 \_\_FILE__ 、 \_\_LINE__ 、 \_\_FUNCTION__ 、$argv 等資訊。其實就是目前列印這行所在函數的相關內容。
我們當然也可以多嵌套幾層函數來看一下列印出的內容是什麼。
function b_test(){ c_test(); } function c_test(){ a_test("b -> c -> a"); } b_test(); // Hi: b -> c -> a // /Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php:7: // array(3) { // [0] => // array(4) { // 'file' => // string(93) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php" // 'line' => // int(37) // 'function' => // string(6) "a_test" // 'args' => // array(1) { // [0] => // string(11) "b -> c -> a" // } // } // [1] => // array(4) { // 'file' => // string(93) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php" // 'line' => // int(33) // 'function' => // string(6) "c_test" // 'args' => // array(0) { // } // } // [2] => // array(4) { // 'file' => // string(93) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php" // 'line' => // int(40) // 'function' => // string(6) "b_test" // 'args' => // array(0) { // } // } // }
沒錯,數組的輸出順序就是一個堆疊的執行順序,b_test() 最先調用,所以它在堆疊底,對應的輸出也就是數組中的最後一個元素。
在類別中也是類似的使用方法。
class A{ function test_a(){ $this->test_b(); } function test_b(){ var_dump(debug_backtrace()); } } $a = new A(); $a->test_a(); // /Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php:90: // array(2) { // [0] => // array(7) { // 'file' => // string(93) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php" // 'line' => // int(87) // 'function' => // string(6) "test_b" // 'class' => // string(1) "A" // 'object' => // class A#1 (0) { // } // 'type' => // string(2) "->" // 'args' => // array(0) { // } // } // [1] => // array(7) { // 'file' => // string(93) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php" // 'line' => // int(95) // 'function' => // string(6) "test_a" // 'class' => // string(1) "A" // 'object' => // class A#1 (0) { // } // 'type' => // string(2) "->" // 'args' => // array(0) { // } // } // }
在類別中使用的時候,在陣列項目中會多出一個 object 字段,顯示的是這個方法所在類別的資訊。
debug_backtrace() 的函數聲明是:
debug_backtrace ([ int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT [, int $limit = 0 ]] ) : array
其中\$options 是有兩個常量可以定義,DEBUG_BACKTRACE_PROVIDE_OBJECT 表明是否填充"object" 的索引;
DEBUG_BACKTRACE_IGNORE_ARGS是否忽略"args" 的索引,包括所有的function/method 的參數,能夠節省記憶體開銷。 $limits 可用來限制傳回堆疊幀的數量,預設為0傳回所有的堆疊。
debug_backtrace() 以及下面要介紹的debug_print_backtrace() 方法都是支援require/include 檔案以及eval() 中的程式碼的,在嵌入檔案時,會輸出嵌入檔案的路徑,這個大家可以自行嘗試。
debug_print_backtrace()
這個方法從名稱也可以看出,它會直接印出回溯內容,它的函數宣告和debug_backtrace() 是一樣的,不過$options 預設是DEBUG_BACKTRACE_IGNORE_ARGS ,也就是說,它只印出呼叫所在檔案及行數。
function a() { b(); } function b() { c(); } function c(){ debug_print_backtrace(); } a(); #0 c() called at [/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php:144] #1 b() called at [/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php:140] #2 a() called at [/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202004/source/PHP打印跟踪调试信息.php:151]
另外就是這個函數不需要使用 var_dump() 或 print_r() 來輸出,直接使用這個函數就會輸出。能夠非常快速方便的讓我們進行調試。
例如在 laravel 這類大型框架中,我們在控制器需要查看堆疊資訊時,就可以使用 debug_print_backtrace() 快速地查看目前的堆疊呼叫情況。而 debug_backtrace() 如果沒有指定 $options 的話,則會佔用非常大的記憶體容量或無法完整顯示。
總結
今天介紹的這兩個函數能夠靈活地幫助我們偵錯程式碼或了解一個框架的呼叫情況。當然,在正式的情況下還是建議使用 Xdebug 加上編輯器的支援來進行斷點調試,因為使用 debug_backtrace() 這兩個方法我們無法看到變數的變化情況。
測試程式碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202004/source/PHP%E6%89%93%E5%8D%B0%E8%B7%9F%E8%B8%AA%E8%B0%83%E8%AF%95%E4%BF%A1%E6%81%AF.php
推薦學習:php影片教學