亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > PHP > 正文

PHP中異常處理的一些方法整理

2024-05-04 23:37:15
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了PHP中異常處理的一些方法整理,盡管PHP并不能說是一種很優秀的語言,但其相關技術依然在不斷得到改進,需要的朋友可以參考下

每一個新的功能添加到PHP運行時會創建一個指數隨機數,通過這樣的方式開發者可以使用和甚至濫用這個新特性。然而,直到一些好的和壞的使用情況陸續出現開發者們才達成了共識。當這些新案例不斷浮現,我們終于可以辨別出什么是最好或最壞的做法。

異常處理在PHP中的確無論如何都不算是一個新的特征。但在本文中,我們將討論在PHP 5.3中基于異常處理的兩個新的特點。第一個是嵌套異常第二是一套SPL(現在的PHP運行機制的一個核心擴展)的擴展的新的異常類型。這兩個新特性,這本書里都能找到最佳實踐值得各位去詳細研究。

特別要注意:這些特性中的一些已經存在于低于5.3的PHP版本之中,或者至少能夠在低于5.3的版本之中被實現. 而當本文提到 PHP 5.3, 并不是嚴責意義上的 PHP 運行時版本. 相反,它意味著代碼庫和項目是采用 PHP 5.3 作為最低版本的,但同時也是在新的發展階段出現的所有最佳實踐. 這個發展階段所凸顯的是特定的幾個像Zend Framework, Symfony, Doctrine 以及 PEAR 這樣的項目所進行的“2.0”嘗試.

背景

PHP 5.2 只有一個異常類 Exception。按照 Zend Framework / PEAR 的開發標準, 這個類是你的庫中所有異常類的基類。如果你創建一個名叫 MyCompany 的庫,按 Zend Framework / PEAR 的標準, 庫中所有的代碼文件都會以 MyCompany_ 開頭。要是你想給庫創建自己的異常基類: MyCompany_Exception, 那就用該類繼承 Exception,然后再由組件(component )繼承和拋出該異常類。比如你有一個組件 MyCompany_Foo,你可以給它創建一個用在該組件內部的異常基類 MyCompany_Foo_Exception。這些異常能被捕捉 MyCompany_Foo_Exception,MyCompany_Exception 或 Exception 的代碼捉到。 對于庫中其他用到該組件的代碼來說,這是個三層的異常(或更多,取決于 MyCompany_Foo_Exception 的子類有幾層 ), 他們可以根據自己的需要處理這些異常。

在php5中,基本異常類已經支持嵌套的特性了。什么是嵌套呢?嵌套是一種能力可以去捕獲特殊異常,或者捕獲參照原始異常而創建的一個新的異常對象。這將會允許caller屬性在更公開的類型的開銷庫中出現的兩種異常類上得到體現,當然也會在具有原始異常行為的異常類上體現。

為什么這些特性很有用?通常,通過使用其他代碼來拋出自己的類型的異常是最有效的代碼。這些代碼可能是使用適配器模式封裝的提供一些適應性更強強的函數的第三方代碼庫的代碼,或利用一些PHP擴展來拋出異常的簡單代碼。

例如,在組件 Zend_Db 中, 它使用了適配器模式來封裝特定的 PHP 擴展,來創建一個數據庫抽象層. 在一個適配器中, Zend_Db 封裝了 PDO, 而 PDO 會拋出它自己的異常 PDOException, Zend_Db 需要捕獲這些特定于 PDO 的異常,并讓它們以可預期且類型已知的 Zend_Db_Exception 重新被拋出. 這樣就給了開發者保證, Zend_Db 將總是拋出 Zend_Db_Exception 類型的異常(因此可以被捕獲), 而他們同時也可以在需要的時候訪問到最開始被拋出的 PDOException.

下面的示例展示了一個虛構的數據庫適配器可能如何去實現嵌入式的異常:

 

 
  1. class MyCompany_Database 
  2. /** 
  3. * @var PDO object setup during construction 
  4. */ 
  5. protected $_pdoResource = null
  6.  
  7. /** 
  8. * @throws MyCompany_Database_Exception 
  9. * @return int 
  10. */ 
  11. public function executeQuery($sql) 
  12. try { 
  13. $numRows = $this->_pdoResource->exec($sql); 
  14. catch (PDOException $e) { 
  15. throw new MyCompany_Database_Exception('Query was unexecutable'null, $e); 
  16. return $numRows; 
  17.  

為了使用嵌入式的異常,你就得調用被捕獲異常的getPrevious()方法:

 

 
  1. // $sql and $connectionParameters assumed 
  2. try { 
  3. $db = new MyCompany_Database('PDO', $connectionParams); 
  4. $db->executeQuery($sql); 
  5. catch (MyCompany_Database_Exception $e) { 
  6. echo 'General Error: ' . $e->getMessage() . "/n"
  7. $pdoException = $e->getPrevious(); 
  8. echo 'PDO Specific error: ' . $pdoException->getMessage() . "/n"

大多數最近被實現的PHP擴展都擁有OO(面向對象)接口. 因此,這些API傾向于拋出異常,而不是發生錯誤終止。PHP中能夠拋出異常的擴展,稍微列舉出幾個就包括有PDO, DOM, Mysqli, Phar, Soap 以及 SQLite.

新特性:新核心異常類型

在PHP 5.3開發中,我們展示了一些有趣的新異常類型。這些異常在PHP 5.2.x中已經存在,但最近還沒到“重新評估”異常的最佳實踐,現在他們會顯得更加引人注目。他們在SPL擴展中得以應用,并在手冊中列出(這里)由于這些新的異常類型是PHP核心的一部分,也是SPL的一部分,它們可以被任何用PHP 5.3(及以上)運行代碼的人使用。雖然在編寫應用程序層的代碼時,看起來不那么重要,但在我們寫或者使用代碼庫時,使用這些新異常類型變得更加重要

那么為什么新異常是普通類型?以前,開發者試圖通過在異常消息提醒中放入更多的內容來賦予異常更多的含義。雖然這樣做是可行的,但是它有幾個缺點。一是你無法捕獲基于消息的異常。這可是一個問題,如果你知道一組代碼是同樣的異常類型與不同的提示消息對應不同異常情況下,處理起來的難度將相當的大。例如,一個認證類,在對$auth->authenticate();;它拋出異常的相同類型的(假設是異常),但不同的消息對應兩個具體的故障:產生故障原因是認證服務器不能達到但是相同的異常類型卻提示失敗的驗證消息不同。在這種情況下(注意,使用異??赡懿皇翘幚碚J證響應最好的方式),這將需要用字符串來解析消息從而處理這兩種不同的情況。

這個問題的解決辦法顯然是通過某種方式對異常進行編碼,這樣就可以在需要辨別如何對這種異常環境做出反應的時候能夠更加容易的查詢到。第一個反應庫是使用異?;惖?code屬性。另一個是通過創建可以被拋出且能描述自身行為的子類或者新的異常類。這兩種方法具有相同的明顯的缺點。兩者都沒有呈現出想這樣的最好的例子。兩者都不被認為是一個標準,因此每個試圖復制這兩種解決方案的項目都會有小的變化,這就迫使使用這需要回到文檔以了解所創建的庫中已經有的具體解決方案?,F在通過使用SPL的新的類型方法,也稱作php標準庫;開發者就可以以同樣的方式在他們的項目中,并且復用這些項目的新的最佳的方法已經出現。

第二個缺點是使用詳細信息的做法使得理解這些異常情況對那些非英語或英語能力有限的開發者來說十分困難。這可能會使的開發者在試圖理解異常信息的含義的過程十分的緩慢。許多開發者也會寫關于異常的文章,因為還未出現一個統一的整合過的標準所要有同這些開發者數量相同的不同的版本來描述異常消息所描述的情況。

所以我如何去使用它們,就用這些讓人無語的密密麻麻的細節描述?

現在在SPL中有總共13個新的異常類型。其中兩個可被視為基類:邏輯異常和運行時異常;兩種都繼承php異常類。其余的方法在邏輯上可以被拆分為3組:動態調用組,邏輯組和運行時組。

動態調用組包含異常 BadFunctionCallException和BadMethodCallException,BadMethodCallException是BadFunctionCallException(LogicException的子類)的子類,這意味著這些異常可以被其直接類型(譯者注:就是異常自身的類型,大家都知道異常有很多種)、LogicException,或者Exception抓到(譯者注:就是catch)你應該在什么時候使用這些?通常,你應該在由一個無法處理的__call()方法產生的情況,或者回調無法不是一個有效的函數(簡單說,當某些東西并非is_callable())時使用。

例如:

 

 
  1. // OO variant 
  2. class Foo 
  3. public function __call($method, $args) 
  4. switch ($method) { 
  5. case 'doBar'/* ... */ break
  6. default
  7. throw new BadMethodCallException('Method ' . $method . ' is not callable by this object'); 
  8.  
  9.  
  10. // procedural variant 
  11. function foo($bar, $baz) { 
  12. $func = 'do' . $baz; 
  13. if (!is_callable($func)) { 
  14. throw new BadFunctionCallException('Function ' . $func . ' is not callable'); 

一個直接的例子,在__call時call_user_func()。這組異常在開發各種API動態方法的調用、函數調用時非常有用,例如這是一個可以被SOAP和XML-RPC客戶端/服務端能夠發送和解釋的請求。

第二組是邏輯(logic )組。這組由DomainException、InvalidArgumentException、LengthException、OutOfRangeException組成。這些異常也是LogicException的子類,當然也是PHP的Exception的子類。在有狀態不定,或者錯誤的方法/函數的參數時使用這些異常。為了更好地理解這一點,我們先看看最后一組異常

最后一組是運行時(runtime )組。它由OutOfBoundsException、OverflowException、RangeException、UnderflowException、UnexpectedValueExceptio組成。這些異常也是RuntimeException的子類,當然也是PHP的Exception的子類。在“運行時”(runtime)的函數、方法發生異常時,這些異常(運行時組)會被調用

邏輯組和運行時組如何一起工作?如果你看看對象的剖析,通常是發生的是兩者之一。首先,對象將跟蹤并改變狀態。這意味著對象通常是不做任何事情。它可能會傳遞結構給它,它可能會通過setter和getter設置一些東西(譯者注:例如$this->foo='foo'),或者,它可能會引用其他對象。第二,當對象不跟蹤或改變狀態,這代表正在操作——做它該做的事。這是對象的運行時(runtime)。例如,在對象的一生中,它可能被創建,設置一些東西,那么它可能會被setFoo($foo),setBar($bar)。在這些時候,任何類型的LogicException應該被提高。此外,當對象內的方法被帶參數調用時,例如$object->doSomething($someVariation);在前幾行檢查$someVariation變量時,可能拋出一個LogicException。完成檢查$someVariation后,它繼續做它該做的doSomething(),這時被認為是它的“運行時”(runtime),在這段代碼中,可能拋出RuntimeExcpetions異常。

要理解得更好,我們來看看這個概念在代碼中的運用:

 

 
  1. class Foo 
  2. protected $number = 0; 
  3. protected $bar = null
  4.  
  5. public function __construct($options) 
  6. /** 本方法拋出LogicException異常 **/ 
  7.  
  8. public function setNumber($number) 
  9. /** 本方法拋出LogicException異常 **/ 
  10.  
  11. public function setBar(Bar $bar) 
  12. /** 本方法拋出LogicException異常 **/ 
  13.  
  14. public function doSomething($differentNumber) 
  15. if ($differentNumber != $expectedCondition) { 
  16. /** 在這里,拋出LogicException異常 **/ 
  17.  
  18. /** 
  19. * 在這里,本方法拋出RuntimeException異常 
  20. */ 
  21.  

現在理解了這一概念,那么,對代碼庫的使用者來說,這是做什么的呢?使用者可以隨時確定對象的異常狀態,他們可以用異常的具體的類型來捕獲(catch)異常,例如InvalidArgumentException或LengthException,至少也是LogicException。通過這種級別的精度調整,和類型的多樣,他們可以用LogicException捕獲最小的異常,但也可以通過實際的異常類型獲得更好的理解。同樣的概念也適用于運行時的異常,可以拋出更多的特定類型的異常,并且不論是特定或非特定類型的異常,都可以被捕獲(catch)。它可以給使用者提供更詳細的情況和精確度。

下面是一個關于SPL異常的表,您可能會有興趣

類庫代碼中的最佳實踐

PHP 5.3 帶來了新的異常類型, 同時也帶給我們新的最佳實踐. 除了將某些特定的異常(如: InvalidArgumentException, RuntimeException)標準化外, 捕捉組件級的異常, 也很重要. 關于這方面, ZF2 wiki 和 PEAR2 wiki 上面有深入的探討.

簡而言之, 除了上面提到的各種最佳實踐, 我們還應該用 Marker Interface 來創建一個組件級的異?;? 通過創建組件級的 Marker Interface, 用在組件內部的異常既能繼承 SPL 的異常類型, 也能在運行時被各種代碼捕捉. 我們來看下列代碼:

 

 
  1. // usage of bracket syntax for brevity 
  2. namespace MyCompany/Component { 
  3.  
  4. interface Exception 
  5. {} 
  6.  
  7. class UnexpectedValueException  
  8. extends /UnexpectedValueException  
  9. implements Exception 
  10. {} 
  11.  
  12. class Component 
  13. public static function doSomething() 
  14. if ($somethingExceptionalHappens) { 
  15. throw new UnexpectedValueException('Something bad happened'); 
  16.  

如果調用上面代碼中的 MyCompany/Component/Component::doSomething() 函數, doSomething() 拋出的異??梢援斪飨铝挟惓n愋筒蹲? PHP 的 Exception, SPL 的 UnexpectedValueException, SPL 的 RuntimeException, 該組件的MyCompany/Component/UnexpectedValueException, 或該組件的 MyCompany/Component/Exception. 這為捕捉你的類庫組件中的異常提供了極大的便利. 此外, 通過分析異常的類型, 我們也能看出某個異常的含義.

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品在线观| 欧亚精品中文字幕| 久久91亚洲精品中文字幕奶水| 成人精品视频久久久久| 欧美一区二区三区四区在线| 久久精品电影一区二区| 夜夜躁日日躁狠狠久久88av| 日韩亚洲欧美中文在线| 久久国产精品久久精品| 日韩av免费在线播放| 国产精品免费小视频| 久久久久久有精品国产| 欧美激情xxxx性bbbb| 欧美一区二区视频97| 情事1991在线| 欧美成人精品在线观看| 国产精品久久久久久久久久小说| 欧美激情视频网站| 亚洲品质视频自拍网| 国产有码一区二区| 久久手机精品视频| 国产一区二区三区直播精品电影| 久久精品成人欧美大片| 国产亚洲精品va在线观看| 亚洲精品久久久久| 色777狠狠综合秋免鲁丝| 日本精品久久中文字幕佐佐木| …久久精品99久久香蕉国产| 亚洲国产天堂久久综合网| 欧美亚洲一区在线| 久久视频在线观看免费| 欧美福利在线观看| 亚洲国产精品嫩草影院久久| 91天堂在线视频| 久久久噜久噜久久综合| 91精品国产亚洲| 精品国产电影一区| 久久久精品在线观看| 成人午夜一级二级三级| 精品久久久在线观看| 国产精品久久久久免费a∨大胸| 国产精品视频最多的网站| 国产精品久久综合av爱欲tv| 欧美电影在线播放| 欧美成人精品影院| 亚洲第一男人天堂| 国产成人精品一区二区三区| 亚洲老头老太hd| 久久久国产视频| 亚洲专区国产精品| 欧美日韩成人在线观看| 欧美天堂在线观看| 亚洲欧美另类国产| 欧美午夜激情在线| 91九色单男在线观看| 亚洲精品久久久久久久久久久久久| 中文字幕精品—区二区| 中文字幕日韩欧美| 91精品国产乱码久久久久久蜜臀| 一区二区三区回区在观看免费视频| 日韩在线国产精品| 欧美理论在线观看| 欧美激情一区二区三区成人| 欧美精品18videosex性欧美| 2024亚洲男人天堂| xxav国产精品美女主播| 久久av在线播放| 91香蕉电影院| 久操成人在线视频| 国产一区二区三区四区福利| 成人97在线观看视频| 欧美大片在线看| www.日韩免费| 国产日韩精品在线| 国产亚洲精品久久久优势| 欧美性在线观看| 久久99视频免费| 欧美整片在线观看| 91精品国产网站| 欧美性资源免费| 国产有码在线一区二区视频| 精品色蜜蜜精品视频在线观看| 欧美一级视频一区二区| 成人av番号网| 欧美激情视频网址| 久久频这里精品99香蕉| 日韩电影免费在线观看中文字幕| 日韩视频免费中文字幕| 久久久久日韩精品久久久男男| 日韩精品中文字幕久久臀| 久久亚洲精品中文字幕冲田杏梨| 亚州成人av在线| 久久久久这里只有精品| 亚洲片av在线| 国产精品欧美一区二区三区奶水| 久久亚洲影音av资源网| 91久久久久久久一区二区| 国产精品欧美激情在线播放| 日韩中文在线观看| 97视频在线观看播放| 日韩国产中文字幕| 成人午夜一级二级三级| 国产91ⅴ在线精品免费观看| 欧美不卡视频一区发布| 91精品视频专区| 成人美女免费网站视频| 一区二区三区四区视频| 久久精品国产清自在天天线| 992tv成人免费影院| 2020国产精品视频| 国产精品亚洲视频在线观看| 成人字幕网zmw| 日韩中文字幕免费| 日韩成人激情视频| 亚洲天堂第二页| 亚洲精品国产拍免费91在线| 国产精品吊钟奶在线| 一区二区成人精品| yellow中文字幕久久| 亚洲黄色www网站| 在线视频日本亚洲性| 97视频免费在线观看| 2020久久国产精品| 国产成人精品免费久久久久| 欧美老妇交乱视频| 91大神在线播放精品| 久久久99久久精品女同性| 国产精品91在线观看| 中文在线资源观看视频网站免费不卡| 免费91在线视频| 欧美日韩精品在线| 国产精品免费久久久| 日本电影亚洲天堂| 日韩亚洲一区二区| 8050国产精品久久久久久| 国产精品免费观看在线| 欧美日韩黄色大片| 国产男人精品视频| 色先锋久久影院av| 庆余年2免费日韩剧观看大牛| …久久精品99久久香蕉国产| 欧美日韩国产在线| 美女视频黄免费的亚洲男人天堂| 97免费视频在线播放| 国产精品久久久久久久久久久久久久| 国产精品成人观看视频国产奇米| 美女国内精品自产拍在线播放| 久久精品视频一| 日韩在线中文视频| 亚洲欧美www| 国产精自产拍久久久久久蜜| 91九色国产在线| 亚洲乱码av中文一区二区| 欧美电影免费播放| 蜜月aⅴ免费一区二区三区| 久久久国产精彩视频美女艺术照福利| 久久久久久久久久久久久久久久久久av| 亚洲第一av网站| 日韩午夜在线视频| 欧美裸体xxxx极品少妇| 91在线|亚洲| 国产国产精品人在线视| 91黑丝在线观看| 高清欧美性猛交xxxx|