雖然您可以使用 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 網站還有其他一些故障檢修技巧。