2009-10-26 22 views
1

我相信,在正確編碼的系統中 - 錯誤(作爲錯誤或異常)不應該是可能的(除了DB/memcached服務器關閉導致查詢失敗)。我們的守則不應該依賴任何假設來正確工作,並且應該儘可能地防患於未然。然而,爲了確保我們的系統以最友好的方式處理問題,我們必須構建並實施某種「捕獲系統」,以確保如果出現任何問題,我們的服務人員和最終用戶將得到照顧。PHP異常真的比錯誤更有用嗎? (Adv)

爲此,PHP提供了兩種解決方案 - 錯誤和例外。錯誤由5個值組成,而Exceptions由包含在對象中的5個值組成。兩者都允許在應用程序構建時具有無價之寶。

5個值爲$ ERROR_CODE, $ ERROR_MESSAGE,$文件,$線,$背景

通常情況下,在我們爭取適當的OOP編程的默認選擇始終追求的對象 - 但在這樣的情況下,我不確定他們真的是多麼有益。通過使用異常,添加內存被浪費在需要將值包裝在對象中(這通常還需要包含異常類的額外文件)。此外,您必須在TRY/CATCH塊中包裝任何您認爲可能失敗的代碼。這使得錯誤處理方法對於人爲錯誤是開放的,因爲開發人員可能不會覆蓋失敗點。爲了安全防範這種情況,您可以使用set_exception_handler,它將傳遞任何未捕獲的異常。異常處理程序的壞處在於執行會在調用exception_handler後停止 - 因此,如果不能在try/catch塊中捕獲異常,則不存在可恢復/忽略的異常。

另一方面,錯誤總是全局的,可以由set_error_handler設置的任何函數/類來處理。這消除了額外的異常類,對象內存或try/catch代碼行的需要。像例外情況一樣,錯誤代碼也可以通過內置錯誤代碼來實現(與例外情況不同),您可以使用這些代碼繼續執行腳本以執行輕微或不重要的腳本問題。另外,大多數PHP函數都會觸發錯誤,所以不會違背語言的流程。

因此,既然您必須支持錯誤處理(對PHP語言做),那麼浪費額外代碼和內存的目的是什麼也實現異常?我們是否盲目地這麼做,是因爲它在對象形式上是錯誤的,還是在應用程序設計中有一個真正的好處,那就是正常的錯誤不能提供給我們?

回答

4

我相信錯誤例外的定義之間存在哲學上的區別。

一個錯誤簡單地說就是一個編程缺陷,由代碼中的邏輯謬誤產生。傳遞strlen()不正確的參數個數應該是錯誤的。一個例外,在另一方面,處理的一切是正確編程的情況下,但你的代碼與資源的代碼庫(文件系統,網絡服務,外部可執行等)以外的交互。雖然預計這種外部資源應該在每次調用時都能正常工作,但會出現不屬於程序控制範圍的情況 - 這些情況不歸因於代碼故障(文件系統被取消掛載,連接超時等) 。由於這些問題是由於外部因素造成的,因此它們被視爲例外。

的主要區別是,一個人的自己的代碼中出現錯誤,而在第三方資源發現異常的情況下發生異常。

+1

這不完全正確。假設你有一些函數'A'和'B',其中'A'用值'C'調用'B',可以拋開語義上的爭論。 ''C'可能不適合與'B'一起使用 - 因此,使用你的定義是一個*錯誤*,一個「代碼中的邏輯謬誤」。但錯誤不在'B'函數中,它在函數'C'到'B' - 函數'A'中。那麼怎麼能'B'發信號給'A',說明'A'有錯誤?或者,根據你的代碼,'B'怎麼可以給'Z',那個叫'A'的函數,'A'有錯誤?這是一個例外。 – 2009-10-26 20:41:26

+0

這聽起來沒問題,但是'A'沒有編程以將正確的數據類型傳遞給'B'並不是一個例外 - 這是一個「代碼中的謬誤」。應該正確地重寫A'以遵守'B'設定的標準。現在如果'A'無法知道'B'想要什麼 - 那將是一個例外。 – Xeoncross 2009-10-30 22:31:04

8

我停止了這一行後閱讀:

我相信,在正確編碼 系統 - 錯誤(如錯誤或 例外)應該是不可能的 (用DB/memcached的 服務器除外導致查詢失敗,導致 失敗)。

這是全部目的例外 - 作爲一個結構中的代碼來管理特殊情況

如果您拋出異常作爲un例外的普通程序流的一部分,那麼您做錯了什麼。

如果你不知道爲什麼例外是特殊情況下非常有用,那麼也許你需要花一些時間與真正的面向對象的語言。 (提示:PHP是不是一個真正的面向對象的語言。)

+1

這是一個非常有效的觀點。我主要解決的是在PHP框架中使用異常來處理最常見的錯誤。特殊情況,即對RAM和CPU之外的任何請求(DB /另一臺服務器/等)都可能從中受益。 – Xeoncross 2009-10-26 17:37:44

+0

在一個框架中,拋出異常是一個好主意。任何時候一個功能都無法執行它要求的操作,這是一種特殊情況。對於函數來說,通過拋出異常來進行響應是非常合適的,並將這種異常情況通知給調用者。從本質上講,通過拋出一個異常,您可以給調用者選擇處理情況*本地*(使用try/catch塊)或更高級別(可能全局)。任何其他錯誤機制都不提供該選擇。 – 2009-10-26 20:35:56

4

隨着所有這些錯誤來延長異常的巨大優勢面向對象的方法。

因此,您可以在一個catch塊(FileNotFoundException,FileNotWritableException,...)中捕獲IOExceptions的所有子異常,以及另一個異常(其中可能會再次拋出該異常):

try 
{ 
    // [...] (some code causing the exception) 
} 
catch(IOException $e) 
{ 
    // do your processing here, like let's say set correct filemodes. 
} 
catch(Exception $e) 
{ 
    // catches all other exceptions 
} 

此外,他們爲您提供關於您如何在您的腳本處理錯誤更標準化的方式。當您使用try/catch塊,錯誤處理幾乎總是看起來很相似,在許多情況下,更是不言自明的比使用正常的錯誤有哪一個能您更好地理解代碼等

:?

switch($errorCode) 
{ 
    case 1450: 
     // Create the database column 
     break; 
} 

// or 

catch(ColumnNotFoundException $e) 
{ 
    // Create the database column 
} 
+0

所以你要說的是,在這種情況下他們提供的優勢是在處理錯誤時更精細的控制。由於PHP只有大約9種左右的錯誤類型 - 通過使用異常,您可以添加新的類型,如IO錯誤,快樂錯誤等...... – Xeoncross 2009-10-26 17:43:19

+0

是的。另外,它們提供了更加標準化的處理錯誤的方法。 – 2009-10-26 17:46:10

+0

如何?請解釋說明。 – Xeoncross 2009-10-26 17:47:52

0

函數fopen()函數具有返回以下的可能性:

如果打開失敗,將生成 E_WARNING一個級別的錯誤。您可以使用@ 來抑制此警告。

您可以選擇使用抑制運算符,但它本身會產生相當數量的開銷。 try/catch塊使您能夠捕獲此錯誤,繼續定期執行,向用戶顯示自定義錯誤,並一舉記錄錯誤。對我來說,在我的文檔中利用異常處理的好處是毫不費力的。

另外,如果你使用任何一塊Zend框架(包括任何的谷歌API的類),則預計將在處理自己的異常,因爲他們做的和將發生。

+0

PHP中的try/catch塊是否也會捕獲PHP函數引發的錯誤?我不知道:) – 2009-10-26 17:43:38

+0

這個聲明的問題是,你可以做所有上面的錯誤,所以切換到異常沒有任何好處。但是,我同意世界上沒有任何代碼應該使用@符號,因爲浪費了資源。這只是針對不瞭解錯誤處理的初學者。 – Xeoncross 2009-10-26 17:45:56

+0

是的,你可以有效地抓住一切,但不包括致命錯誤: http://www.phpdevblog.net/2008/11/catching-warnings-and-notices.html – 2009-10-26 18:33:14