我們什麼時候應該使用異常?_PHP教程

來源:互聯網
上載者:User
先說個題外話: 在公司做了倆件事, 是我覺得很有意義的, 第一就是成立了一個PHP郵件組, 第二就是成立了一個Hi群. 目前倆者都有超過500 phpers在裡面. 我一直認為, 構建一個交流平台, 讓同學們能順暢, 簡單的溝通, 是營造積極的技術學習氛圍的基礎和前提. 讓每個人的問題不會成為別人的問題, 則是最直接的利益. (後記: 不少人都問郵件組地址, 實在不好意思, 這個郵件組是公司內部的郵件組, Hi也是公司內部的. 謝謝)

昨天, 有同事在郵件組提了個問題:

PHP應該什麼時候使用 Exception ? 它的效能如何?

這個問題也算是一個久經爭論的經典問題了. 我談談我的個人看法.

異常與之對應的錯誤碼(或者狀態代碼), 到底各自有什麼優點, 缺點, 我們應該怎麼使用呢?

錯誤碼

首先來說, 異常機制是在錯誤碼機制之後才出現的, 那麼根據進化論, 異常自然是避免了錯誤碼機制的一些不足. 這些不足包括.

1. 錯誤資訊不豐富

函數, 只能有一個傳回值(當然, Lua可以返回多個, 但其實也相當於在PHP中返回一個數組), 我們見過最多的函數說明就是: 成功時候返回***, 錯誤的時候返回FALSE, 然而一個函數出錯我原因可能有多種, 出錯的種類更有多種. 一個簡單的FALSE, 並不能把具體的錯誤資訊告訴調用者.

於是, 我們也就見過一些, 這樣的函數說明: 如果傳回值大於0, 則表示成功的狀態代碼, 如果傳回值小於0, 則表示出錯的狀態代碼.

然而, 這個要求函數是返回整形(或者數字), 對於一些其他函數, 我們並不能通過0, >0, <0來判別, 並且, 即使通過這樣的方式, 我們還需要用返回的錯誤碼和一些預定義宏(或者調用類似strerror())來擷取具體的, 可讀的錯誤資訊.

於是, 就有一些函數使用全域的錯誤碼, 和錯誤資訊, 來儲存具體的錯誤資訊, 這個時候我們就看到這樣的函數描述: 成功返回***, 出錯的時候返回FALSE, 錯誤碼儲存在全域變數$errno中(至少大多數Linux庫函數是這樣描述的, 呵呵).

Okey, 這樣的方式確實可以工作, 但是, 是不是覺得, 很醜陋呢?

2. 加入錯誤狀態代碼可能需要改變函數簽名

假設, 你編寫了一個函數, 這個函數很簡單, 很簡單, 你認為他絕對不會出錯, 於是你申明為(用C語言為例, PHP沒有傳回型別提示):

 
  1. void dummy() {
  2. }

但是後來你慢慢修改了這個函數, 給了它更多的功能, 此時這個函數可能會失敗了. 而你現在根本無法為這個函數, 加入錯誤返回碼了.

也許有人說PHP沒有傳回值類型限制一說, 但是想想PHP的建構函式, 建構函式是沒有傳回值的, 當發生錯誤的時候, 如果你不使用異常, 我想你只能選擇die, 或者使用2中的方法來錯誤繼續執行了.

另外, 在一個良好的軟體系統中, 傳回型別其實也是約定俗成的, 當所有的使用的函數的地方, 都沒有檢查傳回值的時候, 你還是無法為這個函數加入錯誤返回碼.

3. 錯誤狀態代碼可能會被忽略

當你的一個函數, 出錯了, 返回了錯誤狀態代碼, 而調用方並沒有檢測這個傳回值, 會發生什麼情況呢? -_#. 令一方面, 處處檢測返回狀態代碼, 會造成代碼非常的,,ugly:

 
  1. if (!call1()) {
  2. die();
  3. }
  4. if (call2() != SUCCESS) {
  5. die();
  6. }
  7. if (call3() < 0) {
  8. $msg = error_get_last();
  9. die($msg["message"]);
  10. }

異常機制

那麼現在我們來看看異常機制, 如果我們採用異常機制, 上面的代碼可以寫作:

 
  1. try {
  2. call1();
  3. call2();
  4. call3();
  5. } catch (Exception $e) {
  6. die($e->getMessage());
  7. }

更方便的, 如果你的代碼只是中介層, 你的調用方會負責處理錯誤的話, 你甚至可以簡單的寫作:

 
  1. function myFunc() {
  2. call1();
  3. call2();
  4. call3();
  5. }

而一個異常對象, 可以包含更豐富的錯誤資訊, 比如錯誤資訊, 錯誤碼, 錯誤的行數, 檔案, 甚至出錯上下文, 等等, 避免的”1.錯誤資訊不豐富”的不足.

我們也可以為一個返回void類型的函數增加異常, 而不改變他的函數簽名, 也就不會有上面說的”2.加入錯誤狀態代碼可能需要改變函數簽名”. 對於PHP來說, 如果我們新加入的錯誤沒有被捕捉, 也不用擔心, 會明顯的出錯的. 也就不會發生上面所說的”3. 錯誤狀態代碼可能會被忽略”的情況.

然而, 也有一些反對使用異常的聲音:

1. 效能

正如文章開頭提問中的: “它的效能如何?”, 異常機制確實要比返回狀態代碼的方式昂貴一些, 對於C++來說, 在異常發生的時候, 還要發生堆棧解退。

效能和方便, 往往是一個矛盾體, 我只能說, 你需要權衡, 如果你寫的是一個小的模組, 並且它的生命期可能很短, 也不需要什麼特殊的設計模式, 那我覺得你可以不用異常.

而如果你在為一個龐大的軟體做開發, 我想你更應該看重的, 應該是, 它的可擴充性, 可維護性.

2. 太多可能的Uncaught Exception

如果, 你調用了一個可能發生異常的函數, 但是卻沒有捕獲這個異常, okey, Fatal Error了, 所以讓我們的代碼看起來:

 
  1. try {
  2. } catch () {
  3. }....
  4. try {
  5. } catch () {
  6. }....
  7. try {
  8. } catch () {
  9. }

然而, 這個是可以經過良好設計避免的, 比如我在設計

http://www.bkjia.com/PHPjc/445671.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/445671.htmlTechArticle先說個題外話: 在公司做了倆件事, 是我覺得很有意義的, 第一就是成立了一個PHP郵件組, 第二就是成立了一個Hi群. 目前倆者都有超過500 ph...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.