雖然您可以使用 PHP 為系統管理和傳統數據處理之類的任務創建命令行腳本,但是編程語言對 Web 應用程序的性能有主要影響。在使用過程中,每個 PHP 應用程序都駐留在服務器上,並且將通過代理(例如 Apache)調用 PHP 應用程序處理到來的請求。對於每個請求,典型的 PHP Web 應用程序在簡短運行後將得到一個 Web 頁面或 XML 數據結構。
假定經過簡單的運行後,一個分層構造的 Web 應用程序 —— 包括客戶機、網絡、HTTP 服務器、應用程序代碼和底層數據庫 —— 將會很難隔離 PHP 代碼中的錯誤。即使假定除了 PHP 代碼以外所有層都可以正常運行,跟蹤 PHP 代碼中的錯誤也會非常難,尤其是在應用程序利用較多的類時更是如此。
PHP 語句 echo 和函數 var_dump()、debug_zval_dump() 和 print_r() 都是常見且流行的調試輔助工具,可以幫助解決多種問題。但是,這些語句 —— 甚至更健壯的工具,例如 PEAR Log package —— 都是取證工具,必須在上下文環境之外先進行推測分析才能生成證據。
在某種程度上,通過推論進行調試是一種蠻干的做法。收集並篩選數據,嘗試推論出發生的問題。如果缺少重要信息,則必須重新測試代碼、重復執行步驟,然後重新開始研究。一種更加高效的方法是在 程序運行時探測應用程序。您可以對請求參數分類,篩選過程調用堆棧,並查詢任何所需的變量或對象。您可以暫時中斷應用程序並且可以在變量更改值時收到警報。在某些情況下,您可以通過交互式詢問 “如果……會怎樣?” 問題來實際影響變量。
稱為調試器 的特殊應用程序支持這種 “實時的” 或交互式的檢查。調試器可能啟動並連接到進程上以便控制進程並監測其內存。或者,在使用解釋語言的情況下,調試器可以直接解釋代碼。典型的現代圖形化調試器可以索引並浏覽代碼,以符合人類閱讀習慣的形式輕松地顯示復雜的數據結構,並同時顯示程序狀態,如調用堆棧、中間輸出和所有變量的值。例如,調試器通常都會把類的屬性和方法分類並進行描述。
在本文和下一篇文章中,我將介紹的工具一定能夠簡化 PHP 調試。下一次,我將主要介紹交互式調試和 Zend Debugger —— 一個特別針對 PHP 的健壯調試器 —— 並探究它提供的許多功能。(Zend Debugger 是一款商業產品,是 Zend PHP 集成開發環境(IDE)的一部分)。我還將介紹一款開源 PHP 調試器,以免您只願把錢花在啤酒上,而不是花在代碼上。但是,本文將主要介紹如何更好地取證。
類似《犯罪現場調查》,只是更令人討厭
代碼出錯、未能生成某個所需結果或者徹底崩潰時,您需要回答四個 w 問題:where、what、why 和 when:
“where” 是應用程序最後一次正常運行時所在的文件和行號。
“what” 是犯錯的代碼 —— 比如說,嫌疑犯。
“why” 是錯誤的本質。可能它是一個邏輯錯誤和/或與操作系統進行交互所導致的錯誤,或兩者兼具。
而 “when” 是出現錯誤時的上下文。在程序終止前發生了什麼情況?像在所有犯罪行為中一樣,如果您可以收集到足夠的線索,那麼線索就可以幫助您找到犯人。
一種取證工具 Xdebug(上一篇文章中使用的工具,用於分析 PHP 應用程序性能),如名稱所示,將提供幾個說明程序狀態的功能,並且是應當添加到指令系統中的價值頗高的研究工具(請參閱 參考資料)。安裝後,Xdebug 將阻止無限次遞歸(表面上是這樣)、修正關於堆棧跟蹤和函數跟蹤的錯誤消息以及監視內存分配,並提供其他功能。Xdebug 還包括一組函數,您可以將這組函數添加到代碼中以進行運行時錯誤診斷。
例如,下面的代碼將使用一些 xdebug_...() 步驟測試 callee() 函數,以便輸出調用程序的具體位置,包括文件名、行號和調用函數的名稱。
清單 1. 測試 callee() 函數的步驟
function callee( $a ) {
echo sprintf("callee() called @ %s: %s from %s",
xdebug_call_file(),
xdebug_call_line(),
xdebug_call_function()
);
}
$result = callee( "arg" );
?>
這段代碼將生成:
callee() called @ /var/www/catalog/xd.php: 10 from {main}
回頁首構建和安裝 Xdebug
Xdebug 可以很輕松地從 UNIX® 類操作系統(包括 Mac OS X)中的源代碼構建。如果是在 Microsoft® Windows® 上使用 PHP,則可以從 Xdebug Web 站點下載最新 PHP 版本的二進制 Xdebug 模塊(請參閱 參考資料)。
讓我們來構建和安裝適用於 Debian “Sarge” Linux® 和 PHP V4.3.10-19 的 Xdebug。在撰寫本文時,Xdebug 的最新版本是 V2.0.0RC4,發布於 2007 年 5 月 17 日。要繼續本文,必須擁有 phpize 和 php-config 實用程序,並且必須能夠編輯系統的 php.ini 配置文件(如果沒有實用程序,請訪問 PHP.net 以獲得如何從頭構建 PHP 的源代碼和說明)。請執行以下步驟:
下載 Xdebug tarball(一個用 gzip 壓縮的 .tar 歸檔文件)。wget 命令可以幫助您輕松地完成此操作: $ wget http://www.xdebug.org/files/xdebug-2.0.0RC4.tgz
解壓縮該 tarball 並切換到源代碼目錄:$ tar xzf xdebug-2.0.0RC4.tgz
$ cd xdebug-2.0.0RC4
運行 phpize 以准備適用於您的 PHP 版本的 Xdebug 代碼:$ phpize
Configuring for:
PHP Api Version: 20020918
Zend Module Api No: 20020429
Zend Extension Api No: 20021010
phpize 的輸出是一個腳本 —— 通常名為配置 —— 用於調整其余的構建過程。
運行配置腳本:$ ./configure
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
...
checking whether stripping libraries is possible... yes
appending configuration tag "F77" to libtool
configure: creating ./config.status
config.status: creating config.h
通過運行 make 構建 Xdebug 擴展:$ make
/bin/sh /home/strike/tmp/xdebug-2.0.0RC4/libtool
--mode=compile gcc -I.
-I/home/strike/tmp/xdebug-2.0.0RC4 -DPHP_ATOM_INC
-I/home/strike/tmp/xdebug-2.0.0RC4/include
-I/home/strike/tmp/xdebug-2.0.0RC4/main
-I/home/strike/tmp/xdebug-2.0.0RC4
-I/usr/include/php4 -I/usr/include/php4/main
-I/usr/include/php4/Zend -I/usr/include/php4/TSRM
-DHAVE_CONFIG_H -g -O0 -c
/home/strike/tmp/xdebug-2.0.0RC4/xdebug.c -o
xdebug.lo mkdir .libs
...
Build complete.
(It is safe to ignore warnings about tempnam and tmpnam).
使用 make 將生成 Xdebug 擴展 xdebug.so。
安裝該擴展:$ sudo make install
Installing shared extensions: /usr/lib/php4/20020429/
繼續之前,使用鼠標選擇並復制上一條命令顯示的目錄。該路徑對於最後一步配置擴展至關重要。
在您喜歡的文本編輯器中打開 php.ini 文件,然後添加以下代碼:zend_extension = /usr/lib/php4/20020429/xdebug.so
xdebug.profiler_enable = Off
xdebug.default_enable = On
第一行將裝入 Xdebug 擴展;第二行將禁用 Xdebug 的分析器功能(只是為了簡單起見),而第三行將啟用擴展的調試功能。
要檢驗 Xdebug 擴展是否已經安裝並啟用,請重新啟動 Web 服務器,然後用代碼 創建簡單的一行 PHP 應用程序。如果將浏覽器指向文件 —— 如 http://localhost/phpinfo.php —— 並向下滾動,您應當會看到類似圖 1 所示的內容。
圖 1. 檢驗 Xdebug 擴展是否已經安裝並運行
注:如果您在 phpinfo() 的輸出中沒有看到 Xdebug 部分,則 Xdebug 裝入失敗。Apache 錯誤日志會列出原因。常見錯誤包括zend_extension 的路徑錯誤或者與其他擴展發生沖突。例如,如果需要使用 XCache 和 Xdebug,一定要先裝入 XCache。但是,由於 Xdebug 適於在開發時使用並假定 xdebug.so 的路徑正確,因此需要禁用其他擴展並重試。然後您可以重新啟用擴展以執行其他測試,如緩存的效果。Xdebug 站點還有其他一些故障檢修技巧。