根據(jù)一個廣為流傳的傳說,第一個計算機 bug 是一只真正的蟲子,,它出現(xiàn)在 Harvard University 測試的 Mark II Aiken Relay Calculator 中的一個繼電器上,。根據(jù)操作員在 1947 年 9 月 9 日所做的日志記錄,這只蟲子是 “(在計算機中)發(fā)現(xiàn)的第一個 bug”,。在圖 1 中可以看到這份手寫的日志記錄和這只聲名狼籍的蟲子,。 圖 1. 聲名狼籍的 Mark II 蟲子實際上,bug 這個詞的起源要早得多,,可能比前面這次事件早了大約七十年,。在 1848 年,Thomas Edison 在描述機械故障時寫道,,“首先是覺得有點兒不對勁兒,,然后是一聲爆響,接著麻煩就來了 —— 機器不正常了,,出現(xiàn)了小故障和各種麻煩等 ‘bug’...” 顯然,,與 Edison 同時代的人已經(jīng)把 bug 這個詞當作行話了。 了解到即使是 Edison 也必須對其發(fā)明進行 “調(diào)試(debug)”,,軟件開發(fā)人員可能會覺得有所慰藉并受到鼓舞(Edison 沒有用過 debug 這個詞,。這個詞比較新,,它是在二戰(zhàn)時期從航空工業(yè)開始成為工程師的行話的)?;蛘?,您可能希望所有的 bug 都是真正的蟲子,那倒好辦了,,我們只需安裝一個捕蟲器就行了,。“計算機 bug 進得來,,但是出不去,。”(有人能在 Subversion 的下一版中增加這個特性嗎,?) 但是,,正如 Edison 所指出的,bug 是每個工程項目的固有部分,。在討論發(fā)明時,,Edison 寫道,“必須經(jīng)過數(shù)月的艱苦觀察,、研究和勞動,,才能讓產(chǎn)品經(jīng)受市場的考驗?!? 幸運的是,,軟件開發(fā)人員可以利用工具簡化 “觀察” 的過程,將花費的時間從幾個月減少到幾分鐘,,至少減少到幾小時或幾天,。以前的一篇文章 “Squash bugs in PHP applications with Xdebug” 介紹了收集分析故障原因所需的信息的各種技術。但是,,這種故障后分析往往很困難,,而且很耗費時間,因為必須做出推測,,然后進行測試,。如果缺少關鍵的信息,那么必須反復研究,、調(diào)整和測試代碼,,這個過程可能要重復許多次。 本文討論一種更高效的調(diào)試技術:交互式調(diào)試(interactive debug),。有一種稱為調(diào)試器(debugger) 的特殊應用程序,,它們可以探測正在運行的代碼,允許在任意的斷點暫停執(zhí)行,,檢查對象,、檢查調(diào)用堆棧和環(huán)境,,甚至允許在運行時修改變量的值。 在本文中,,將使用 Zend Debugger,;它是 Zend 引擎的一個擴展,可以探察正在運行的 PHP 應用程序,??梢悦赓M下載并使用 Zend Debugger。但是,,為了控制 Zend Debugger 和查看它的診斷信息,需要同時使用一個客戶機應用程序,??蛻魴C可以是從命令行運行的簡單程序,也可以是成熟的集成開發(fā)環(huán)境(IDE),,提供編輯器,、代碼補全、圖形化類瀏覽器等特性,。 有好幾種開放源碼客戶機可以與 Zend Debugger 進行交互,,包括開放源碼的 PHP Eclipse 插件。但是,,我喜歡的 PHP IDE 是由 Zend Technologies 提供的 Zend Studio,,這家公司同時提供 PHP 運行時引擎的開放源碼版本和商業(yè)版本。與 PHP 本身不同,,Zend Studio 是一個商業(yè)產(chǎn)品,。可以下載這個軟件并免費使用 30 天,,這段時間足夠您體會它的眾多特性了,;但是在此之后,如果希望繼續(xù)使用它,,就必須購買許可證,。對于我來說,許可證的費用絕對物有所值,。 您應該試試各種客戶機,,尋找適合自己的軟件。例如,,許多 IDE 包含您喜歡的編輯器,,這樣就不需要重新學習一套鍵盤快捷鍵。無論選擇哪種軟件,,當您開始使用調(diào)試器客戶機之后,,很可能會發(fā)現(xiàn)再也離不開它了,。您可以和 安裝 Zend Studio 和 Zend Debugger首先,,下載并安裝 Zend Studio 和 Zend Debugger 軟件,。這里的步驟說明針對 Mac OS X,但是在 Linux? 和 Microsoft? Windows? 操作系統(tǒng)上安裝步驟是相似的,。(Zend Studio Web 頁面為每種平臺提供了安裝說明,。)實際上,可以在本地系統(tǒng)上安裝并運行 Zend Studio,,將調(diào)試器部署在服務器上,,這樣就可以進行遠程代碼調(diào)試。 無論使用哪種平臺,,都要確保系統(tǒng)中運行著 PHP V4 或 PHP V5:Zend 軟件可以與這兩個版本的 PHP 配合工作,。因為 Mac OS X 當前附帶 PHP V4(更精確地說,是 V4.4.7),,所以本文基于這個比較老的 PHP 版本,。 安裝 Zend 工具的步驟如下:
為了檢驗 PHP 和 Web 服務器的運行是否正常,進入 ~/Sites/ 目錄并創(chuàng)建包含以下內(nèi)容的 info.php 文件: <?php phpinfo(); ?> 在瀏覽器中訪問 http://localhost/~username/info.php,,其中的 username 是您的 Mac OS X 登錄名,。如果配置正確,應該會在 圖 4. 檢驗調(diào)試器是否正在工作請注意 順便說一句,如果您覺得這個安裝過程比較復雜,,或者希望節(jié)省時間,,那么可以下載并安裝 Zend Core 或 Zend Platform。這兩個軟件是商業(yè)產(chǎn)品,,但是都預先配置了 Zend Debugger,。本文余下的說明對于 Zend Core 或 Zend Platform 同樣是有效的。 連接 Zend DebuggerZend Studio 和 Zend Debugger 的組合允許遠程控制 Zend 引擎,。Zend Studio 作為控制面板,,顯示關于引擎內(nèi)部機制的信息,。可以看到正在運行的源代碼,、變量的狀態(tài),、Web 環(huán)境的狀態(tài)以及其他數(shù)據(jù)。 Zend Debugger 像是一個代理:它將來自 Zend 引擎的信息轉(zhuǎn)發(fā)給 Zend Studio,,將來自 Zend Studio 的命令轉(zhuǎn)發(fā)給 Zend 引擎,。命令包括各種調(diào)試概念,比如 因此,,為了調(diào)試 PHP 應用程序,要讓 Zend Studio 連接到調(diào)試器,,然后在瀏覽器中訪問應用程序,。當應用程序開始運行時,調(diào)試器作為代理運行并將控制傳遞給 Zend Studio,。這樣開發(fā)人員就可以接管控制權了,。 配置 Zend Studio下面是一種連接 Zend Debugger 的簡單方法(以后我會提供一個比較復雜的腳本并討論更多調(diào)試技巧):
現(xiàn)在,可以編寫并調(diào)試 PHP 代碼了,。 調(diào)試一些簡單的代碼Zend Studio 提供了編寫 PHP 代碼所需的所有工具:一個用來編輯文件的編輯器,;一個文件管理器,用來將許多文件集中在一個項目中,;一個作為參考的 PHP 類和模塊瀏覽器,;一個用來查看中間結果的輸出視圖;一個環(huán)境瀏覽器,,可以直接查看變量,、調(diào)用堆棧和輸出緩沖區(qū),。更好的是,,編輯器是上下文敏感的,可以自動補全 PHP 控制結構,、關鍵字和字符串分隔符,。 首先,在 Zend Studio 頂部中間的 Editor 窗口中單擊鼠標,。輸入 清單 1 所示的代碼片段,,體會一下編輯器的代碼補全特性。這段代碼的意圖是輸出數(shù)字 1-10,。 清單 1. 輸出數(shù)字 1-10<?php $counter = 1; while ( $counter < 10; ) { printf( "%d\n", $counter ); increment( $counter ); } function increment( $i ) { $i++; return; } ?> 輸入完代碼之后,,單擊工具欄中綠色的 Play 按鈕運行代碼。但是,,代碼并沒有輸出 1-10,,而是不停地輸出數(shù)字 1。單擊紅色的 Stop 按鈕停止程序。 這里顯然有 bug,。首先要調(diào)查的是: 圖 6. 在代碼示例中設置的斷點接下來,,單擊 Play 重新啟動應用程序。程序在第 7 行停止執(zhí)行,。Debug Output 面板(在最右邊)包含一些輸出,,Debug 窗口中的 Variables 選項卡顯示變量的列表。數(shù)組標有方括號( 現(xiàn)在單擊工具欄中藍色的向下箭頭,,執(zhí)行函數(shù)中的下一個語句(藍色的向下箭頭和短線的作用是調(diào)用函數(shù),,并前進到調(diào)用者中的下一個語句)。游標現(xiàn)在應該出現(xiàn)在第 11 行,,Variables 選項卡應該只顯示一個變量:形式參數(shù) 再次單擊向下箭頭,,執(zhí)行第 11 行。 圖 7. 堆棧跟蹤再次單擊向下箭頭,,返回第 5 行,。讓人吃驚的是, 單擊 Stop,然后再次單擊 Play,。分步執(zhí)行這個程序,,應該會看到 1, 2, 3, . . . 8, 9。怎么沒有 10 呢,?答案很明顯:這是一個邊界錯誤,。只需將 盡管這個示例是人為制造的,但是它演示了幾種基本的交互式調(diào)試技術:
要想進一步了解 Zend Studio,可以使用 IDE 編寫 PHP 代碼并單擊各個選項卡,,從而研究它的眾多特性,。即使選擇在另一個程序中編輯代碼,也可以利用 Zend Studio 調(diào)試類、方法和單元測試,。在 IDE 中編寫單元測試尤其有幫助,。 調(diào)試 PHP 應用程序當然,PHP 調(diào)試器的真正價值在于實時探察 Web 應用程序,。下面提供一個這樣的場景,。 比薩餅應用程序清單 2 和 清單 3 是一個簡單的 PHP 應用程序,其中包含一個類,、方法和一些包裝器代碼,。清單 2(index.php)所示的應用程序使用 清單 2. 比薩餅訂單應用程序,index.php<?php include_once( 'pizza.class.php' ); $large = new Pizza( 'L', null ); echo $large->price() . '<br />'; $toppings = array(); $toppings[] = 'pepperoni'; $toppings[] = 'sausage'; $xl = new Pizza( 'XL', $toppings ); echo $xl->price() . '<br />'; $special = new Pizza( 'XL' ); $special->add( null ); $special->add( 'pepperoni' ); $special->add( 'pepperoni' ); $special->add( 'anchovies' ); $special->add( 'anchovies' ); $special->add( 'olives' ); echo $special->price() . '<br />'; ?> 清單 3. Pizza 類<?php class Pizza { var $size; var $toppings = array(); var $price; function Pizza( $size = "R", $toppings = null ) { $this->size = $size; $this->toppings = $toppings; } function size() { return( $this->size ); } function price() { $this->price = 10; $multiplier = 1; switch ( $this->size ) { case 'L': $multiplier = 1.25; break; case 'XL': $multiplier = 2; break; } $this->price = $this->price + ( sizeof( $this->toppings() ) ) * $multipler; return( $this->price ); } function toppings() { return( $this->toppings ); } function add( $topping ) { $this->toppings[] = $topping; } } ?> 按照以下步驟創(chuàng)建項目:
我的代碼出了什么問題,?現(xiàn)在可以調(diào)試這個應用程序了。單擊 Play:應用程序運行,,它的輸出出現(xiàn)在 Debug Output 面板中,。輸出如下: Content-type: text/html 10<br />10<br />10<br /> 為什么這三個比薩餅的價格都是 $10?如果看一下 Debug Messages 面板,,答案就清楚了:變量 如果這個 bug 的原因不這么明顯的話(常常是這種情況),,還可以用另一種方法捕捉這個錯誤。雙擊 Pizza.class.php,,將游標放在第 29 行上并選擇 Debug > Add/Remove Breakpoint,。這一行會變成紅色的。雙擊 index.php 并單擊 Play,。程序在第 29 行停止執(zhí)行,。看一下 Debug 窗口,, 作為一個練習,使用 IDE 分步探察另一個 bug,,這是一個導致重復計價的邏輯錯誤,。取消所有斷點,然后在 index.php 中的第 14 行設置一個斷點,。在 圖 13. 錯誤的 Pizza 對象為了糾正這個 bug,,不允許 null 作為有效的配料(這實際上是 index.php 的錯誤,但是可以在 function toppings() { if ( is_array( $this->toppings ) ) { return( array_unique( $this->toppings ) ); } return( 0 ); } function add( $topping ) { if ( ! is_null( $topping ) ) { $this->toppings[] = $topping; } } 連接瀏覽器最后一個練習是在瀏覽器中啟動應用程序并在 IDE 中調(diào)用它。典型的情況是:觀察瀏覽器中的輸出,,與 Web 頁面進行交互,,然后分步執(zhí)行應用程序,觀察它如何做出響應:
如果應用程序包含表單,,那么可以在表單處理函數(shù)上設置斷點并查看輸入的參數(shù),。在 Debug 窗口中可以查看所有全局環(huán)境變量、PHP 全局變量和每個 Web 請求的參數(shù),。 使用 Debug URL 窗口控制應用程序何時暫停,。PHP Web 應用程序通常集中在一個目錄中并包含一個主頁(一般名為 index.php)。主頁上的鏈接指向其他 PHP 頁面,,那些頁面分別提供不同的特性,。例如,,URL .../store/index.php 可能是一個在線商店的主頁;URL .../store/cart/index.php 可能實現(xiàn)購物車,。 可以用 Zend Studio 調(diào)試某個應用程序根目錄中的一個,、幾個或所有 PHP 頁面。例如,,如果購物車出現(xiàn)了錯誤,,那么可以在打開 cart/ 中的任何頁面時啟動調(diào)試會話。也可以在瀏覽主頁 index.php 時啟動調(diào)試會話,,調(diào)試整個應用程序,。 更好的是,可以組合使用 Zend Studio,、Internet Explorer? 或 Mozilla Firefox 以及 Zend Debugger Browser Toolbar,,從而在瀏覽器中直接啟動調(diào)試會話??梢哉{(diào)試當前頁面,、站點上的所有頁面或某個表單的操作。 一種新的工作方式交互式調(diào)試器就像是礦工頭上的礦燈,。診斷問題所需的艱苦勞動突然變得容易了,,我們不必在黑暗中苦苦摸索了 —— 只需設置斷點,分步執(zhí)行代碼,,觀察每個語句發(fā)生的情況,。用一個筆記本記下每次暫停時的情況,觀察并推測原因,。 Zend Studio 不是調(diào)試器的惟一選擇,。試試其他調(diào)試器,尋找最適合您的工作習慣的調(diào)試器,。無論如何,,務必選用一種調(diào)試器。您會發(fā)現(xiàn)編寫代碼時離不開它,。 參考資料學習
獲得產(chǎn)品和技術
|
|