
日期:2006-09-28 作者:喜騰小二 來源:PHPChina
三、
抛出異常
妳可能已經從上麵的程式碼中注意到,妳擷取的是一個稱為QueryException(我們將在後麵實現這個物件)的異常。一個異常類似於一個錯誤,然而卻更俱有一般性。描述一個異常的最好的方法是使用emergency。儘管一個emergency可以不會是“緻命的”,但是還是必須處理它。當在PHP中抛出一個異常時,執行的當前範圍很快地被終止,不管它是一個函式,try..catch塊還是指令檔本身。然後,該異常遍歷調用棧—終止每個執行範圍,直到或者在一個try..catch塊中擷取它或者它到達調用棧的頂部—此時它將生成一個緻命錯誤。
異常處理是PHP
5中的另外一個新特徵,當與OOP聯用時,它能夠實現良好地控制錯誤處理和報告。一個try..catch塊是一種處理異常的重要機制。一旦被擷取,指令檔將會從異常被擷取和被處理的程式碼的下一行繼續執行。
如果查詢失敗,妳需要改變妳的execute函式以抛出一個異常。妳將抛出一個稱為QueryException的自訂異常物件—導緻錯誤的DBQuery物件被傳遞給它。
清單3.抛出一個異常。
| /** *執行當前查詢 * * 執行當前查詢—用提供的參數代替任何點位符 * . * * @參數: mixed $queryParams,... 查詢參數 * @返回:資源A—參考描述執行查詢的資源。 */ public function execute($queryParams = '') { //例如: SELECT * FROM table WHERE name=:1S AND type=:2I AND level=:3N $args = func_get_args(); if ($this->stored_procedure) { /*調用compile函式以得到查詢*/ $query = call_user_func_array(array($this, 'compile'), $args); } else { /*一個存儲過程沒被初始化,因此,作為一種標準查詢來執行之*/ $query = $queryParams; } $result = $this->db->query($query); if (! $result) { throw new QueryException($this); } $this->result = $result; /* 注意現在我們怎麼返回物件本身,這使我們能夠從這個函式的返回結果中調用成員函式 */ return $this; } |
| class DBQuery { /** *在調用compile()或execute()之後存儲查詢的編譯版本 * * @var string $compiledQuery */ protected $compiledQuery; /** * 返回編譯的查詢而不執行它。 * @參數:mixed $params,...查詢參數 * @返回:字串—編譯的查詢 */ public function compile($params='') { if (! $this->stored_procedure) { throw new Exception("存儲過程沒被初始化."); } /*代替參數*/ $params = func_get_args(); //得到函式參數 $query = preg_replace("/(?compile_callback($params, 1, "2")', $this->query); return ($this->compiledQuery = $this->add_strings($query)); //把字串放回查詢中 } public function getDB() { return $this->db; } public function getCompiledQuery() { return $this->compiledQuery; } } |
| /** *查詢異常 * *當試圖執行一個查詢時,如果一個錯誤發生,將由{@link DBQuery}物件抛出錯誤 */ class QueryException extends Exception { /** * 查詢文字 * * @var字串$QueryText; */ protected $QueryText; /** *來自資料庫的錯誤號/程式碼 * * @var字串$ErrorCode */ protected $ErrorNumber; /** *來自資料庫的錯誤訊息 * * @var字串$ErrorMessage */ protected $ErrorMessage; /** *類構造器 * * @參數:DBQuery $db,是抛出異常的查詢物件 */ public function __construct(DBQuery $query) { /*得到調用棧*/ $backtrace = $this->GetTrace(); /*把行和檔案設定到錯誤實際發生的位置*/ if (count($backtrace) > 0) { $x = 1; /*如果查詢類被繼承,那麼我們需要略過由子類所進行的調用*/ while((! isset($backtrace[$x]['line'])) || (isset($backtrace[$x]['class']) && is_subclass_of($backtrace[$x]['class'], 'DBQuery')) || (strpos(strtolower(@$backtrace[$x]['function']), 'call_user_func')) !== false ) { /*迴圈執行,只要沒有行號或調用的函式是DBQuery類的一個子類*/ ++$x; /*如果我們到達棧底,那麼我們使用第一個調用者*/ if (($x) >= count($backtrace)) { $x = count($backtrace); break; } } /*如果上麵的迴圈至少執行一次,那麼我們可以把它減1以尋找實際的引起錯誤的程式碼行 */ if ($x != 1) { $x -= 1; } /*最後,我們可以設定檔案和行號,這應該可以反映出引起錯誤的SQL陳述式*/ $this->line = $backtrace[$x]['line']; $this->file = $backtrace[$x]['file']; } $this->QueryText = $query->getCompiledQuery(); $this->ErrorNumber = $query->getDB()->errno(); $this->ErrorMessage = $query->getDB()->error(); /*調用超類的異常構造器*/ parent::__construct('Query Error', 0); } /** *得到查詢文字 * * @返回字串查詢文字 */ public function GetQueryText() { return $this->QueryText; } /** *得到錯誤號 * * @返回字串錯誤號 */ public function GetErrorNumber() { return $this->ErrorNumber; } /** *得到錯誤訊息 * * @返回字串錯誤訊息 */ public function GetErrorMessage() { return $this->ErrorMessage; } /** *當物件被轉換為一個字串時調用。 * @返回字串 */ public function __toString() { $output = "Query Error in {$this->file} on line {$this->line}nn"; $output .= "Query: {$this->QueryText}n"; $output .= "Error: {$this->ErrorMessage} ({$this->ErrorNumber})nn"; return $output; } } |