成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

異常在 PHP 5.3 中的最佳實(shí)踐

開(kāi)發(fā) 后端 前端
每一個(gè)新的功能添加到PHP運(yùn)行時(shí)會(huì)創(chuàng)建一個(gè)指數(shù)隨機(jī)數(shù),通過(guò)這樣的方式開(kāi)發(fā)者可以使用和甚至濫用這個(gè)新特性。然而,直到一些好的和壞的使用情況陸續(xù)出現(xiàn)開(kāi)發(fā)者們才達(dá)成了共識(shí)。當(dāng)這些新案例不斷浮現(xiàn),我們終于可以辨別出什么是最好或最壞的做法。

每一個(gè)新的功能添加到PHP運(yùn)行時(shí)會(huì)創(chuàng)建一個(gè)指數(shù)隨機(jī)數(shù),通過(guò)這樣的方式開(kāi)發(fā)者可以使用和甚至濫用這個(gè)新特性。然而,直到一些好的和壞的使用情況陸續(xù)出現(xiàn)開(kāi)發(fā)者們才達(dá)成了共識(shí)。當(dāng)這些新案例不斷浮現(xiàn),我們終于可以辨別出什么是***或最壞的做法。

異常處理在PHP中的確無(wú)論如何都不算是一個(gè)新的特征。但在本文中,我們將討論在PHP 5.3中基于異常處理的兩個(gè)新的特點(diǎn)。***個(gè)是嵌套異常第二是一套SPL(現(xiàn)在的PHP運(yùn)行機(jī)制的一個(gè)核心擴(kuò)展)的擴(kuò)展的新的異常類型。這兩個(gè)新特性,這本書(shū)里都能找到***實(shí)踐值得各位去詳細(xì)研究。

特別要注意:這些特性中的一些已經(jīng)存在于低于5.3的PHP版本之中,或者至少能夠在低于5.3的版本之中被實(shí)現(xiàn).  而當(dāng)本文提到 PHP 5.3, 并不是嚴(yán)責(zé)意義上的 PHP 運(yùn)行時(shí)版本. 相反,它意味著代碼庫(kù)和項(xiàng)目是采用 PHP 5.3 作為***版本的,但同時(shí)也是在新的發(fā)展階段出現(xiàn)的所有***實(shí)踐.  這個(gè)發(fā)展階段所凸顯的是特定的幾個(gè)像Zend Framework, Symfony, Doctrine 以及 PEAR 這樣的項(xiàng)目所進(jìn)行的“2.0”嘗試.

背景

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

在php5中,基本異常類已經(jīng)支持嵌套的特性了。什么是嵌套呢?嵌套是一種能力可以去捕獲特殊異常,或者捕獲參照原始異常而創(chuàng)建的一個(gè)新的異常對(duì)象。這將會(huì)允許caller屬性在更公開(kāi)的類型的開(kāi)銷(xiāo)庫(kù)中出現(xiàn)的兩種異常類上得到體現(xiàn),當(dāng)然也會(huì)在具有原始異常行為的異常類上體現(xiàn)。

為什么這些特性很有用?通常,通過(guò)使用其他代碼來(lái)拋出自己的類型的異常是最有效的代碼。這些代碼可能是使用適配器模式封裝的提供一些適應(yīng)性更強(qiáng)強(qiáng)的函數(shù)的第三方代碼庫(kù)的代碼,或利用一些PHP擴(kuò)展來(lái)拋出異常的簡(jiǎn)單代碼。

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

下面的示例展示了一個(gè)虛構(gòu)的數(shù)據(jù)庫(kù)適配器可能如何去實(shí)現(xiàn)嵌入式的異常:

  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.     { 
  13.         try { 
  14.             $numRows = $this->_pdoResource->exec($sql); 
  15.         } catch (PDOException $e) { 
  16.             throw new MyCompany_Database_Exception('Query was unexecutable', null, $e); 
  17.         } 
  18.         return $numRows
  19.     } 
  20.   

為了使用嵌入式的異常,你就得調(diào)用被捕獲異常的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"

大多數(shù)最近被實(shí)現(xiàn)的PHP擴(kuò)展都擁有OO(面向?qū)ο螅┙涌?  因此,這些API傾向于拋出異常,而不是發(fā)生錯(cuò)誤終止。PHP中能夠拋出異常的擴(kuò)展,稍微列舉出幾個(gè)就包括有PDO, DOM, Mysqli, Phar, Soap 以及 SQLite.

新特性:新核心異常類型

在PHP 5.3開(kāi)發(fā)中,我們展示了一些有趣的新異常類型。這些異常在PHP 5.2.x中已經(jīng)存在,但最近還沒(méi)到“重新評(píng)估”異常的***實(shí)踐,現(xiàn)在他們會(huì)顯得更加引人注目。他們?cè)赟PL擴(kuò)展中得以應(yīng)用,并在手冊(cè)中列出(這里)由于這些新的異常類型是PHP核心的一部分,也是SPL的一部分,它們可以被任何用PHP 5.3(及以上)運(yùn)行代碼的人使用。雖然在編寫(xiě)應(yīng)用程序?qū)拥拇a時(shí),看起來(lái)不那么重要,但在我們寫(xiě)或者使用代碼庫(kù)時(shí),使用這些新異常類型變得更加重要

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

這個(gè)問(wèn)題的解決辦法顯然是通過(guò)某種方式對(duì)異常進(jìn)行編碼,這樣就可以在需要辨別如何對(duì)這種異常環(huán)境做出反應(yīng)的時(shí)候能夠更加容易的查詢到。***個(gè)反應(yīng)庫(kù)是使用異常基類的$code屬性。另一個(gè)是通過(guò)創(chuàng)建可以被拋出且能描述自身行為的子類或者新的異常類。這兩種方法具有相同的明顯的缺點(diǎn)。兩者都沒(méi)有呈現(xiàn)出想這樣的***的例子。兩者都不被認(rèn)為是一個(gè)標(biāo)準(zhǔn),因此每個(gè)試圖復(fù)制這兩種解決方案的項(xiàng)目都會(huì)有小的變化,這就迫使使用這需要回到文檔以了解所創(chuàng)建的庫(kù)中已經(jīng)有的具體解決方案?,F(xiàn)在通過(guò)使用SPL的新的類型方法,也稱作php標(biāo)準(zhǔn)庫(kù);開(kāi)發(fā)者就可以以同樣的方式在他們的項(xiàng)目中,并且復(fù)用這些項(xiàng)目的新的***的方法已經(jīng)出現(xiàn)。

第二個(gè)缺點(diǎn)是使用詳細(xì)信息的做法使得理解這些異常情況對(duì)那些非英語(yǔ)或英語(yǔ)能力有限的開(kāi)發(fā)者來(lái)說(shuō)十分困難。這可能會(huì)使的開(kāi)發(fā)者在試圖理解異常信息的含義的過(guò)程十分的緩慢。許多開(kāi)發(fā)者也會(huì)寫(xiě)關(guān)于異常的文章,因?yàn)檫€未出現(xiàn)一個(gè)統(tǒng)一的整合過(guò)的標(biāo)準(zhǔn)所要有同這些開(kāi)發(fā)者數(shù)量相同的不同的版本來(lái)描述異常消息所描述的情況。

所以我如何去使用它們,就用這些讓人無(wú)語(yǔ)的密密麻麻的細(xì)節(jié)描述?

現(xiàn)在在SPL中有總共13個(gè)新的異常類型。其中兩個(gè)可被視為基類:邏輯異常和運(yùn)行時(shí)異常;兩種都繼承php異常類。其余的方法在邏輯上可以被拆分為3組:動(dòng)態(tài)調(diào)用組,邏輯組和運(yùn)行時(shí)組。

動(dòng)態(tài)調(diào)用組包含異常 BadFunctionCallException和BadMethodCallException,BadMethodCallException是BadFunctionCallException(LogicException的子類)的子類,這意味著這些異??梢员黄渲苯宇愋停ㄗg者注:就是異常自身的類型,大家都知道異常有很多種)、LogicException,或者Exception抓到(譯者注:就是catch)你應(yīng)該在什么時(shí)候使用這些?通常,你應(yīng)該在由一個(gè)無(wú)法處理的__call()方法產(chǎn)生的情況,或者回調(diào)無(wú)法不是一個(gè)有效的函數(shù)(簡(jiǎn)單說(shuō),當(dāng)某些東西并非is_callable())時(shí)使用。

例如:

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

一個(gè)直接的例子,在__call時(shí)call_user_func()。這組異常在開(kāi)發(fā)各種API動(dòng)態(tài)方法的調(diào)用、函數(shù)調(diào)用時(shí)非常有用,例如這是一個(gè)可以被SOAP和XML-RPC客戶端/服務(wù)端能夠發(fā)送和解釋的請(qǐng)求。

第二組是邏輯(logic )組。這組由DomainException、InvalidArgumentException、LengthException、OutOfRangeException組成。這些異常也是LogicException的子類,當(dāng)然也是PHP的Exception的子類。在有狀態(tài)不定,或者錯(cuò)誤的方法/函數(shù)的參數(shù)時(shí)使用這些異常。為了更好地理解這一點(diǎn),我們先看看***一組異常

***一組是運(yùn)行時(shí)(runtime )組。它由OutOfBoundsException、OverflowException、RangeException、UnderflowException、UnexpectedValueExceptio組成。這些異常也是RuntimeException的子類,當(dāng)然也是PHP的Exception的子類。在“運(yùn)行時(shí)”(runtime)的函數(shù)、方法發(fā)生異常時(shí),這些異常(運(yùn)行時(shí)組)會(huì)被調(diào)用

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

要理解得更好,我們來(lái)看看這個(gè)概念在代碼中的運(yùn)用:

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

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

下面是一個(gè)關(guān)于SPL異常的表,您可能會(huì)有興趣

類庫(kù)代碼中的***實(shí)踐

PHP 5.3 帶來(lái)了新的異常類型, 同時(shí)也帶給我們新的***實(shí)踐. 除了將某些特定的異常(如: InvalidArgumentException, RuntimeException)標(biāo)準(zhǔn)化外, 捕捉組件級(jí)的異常, 也很重要. 關(guān)于這方面, ZF2 wiki 和 PEAR2 wiki 上面有深入的探討.

簡(jiǎn)而言之, 除了上面提到的各種***實(shí)踐, 我們還應(yīng)該用 Marker Interface 來(lái)創(chuàng)建一個(gè)組件級(jí)的異常基類. 通過(guò)創(chuàng)建組件級(jí)的 Marker Interface, 用在組件內(nèi)部的異常既能繼承 SPL 的異常類型, 也能在運(yùn)行時(shí)被各種代碼捕捉. 我們來(lái)看下列代碼:

  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.     { 
  14.         public static function doSomething() 
  15.         { 
  16.             if ($somethingExceptionalHappens) { 
  17.                 throw new UnexpectedValueException('Something bad happened'); 
  18.             } 
  19.         } 
  20.     } 
  21.   

如果調(diào)用上面代碼中的 MyCompany\Component\Component::doSomething() 函數(shù), doSomething() 拋出的異??梢援?dāng)作下列異常類型捕捉: PHP 的 Exception, SPL 的 UnexpectedValueException, SPL 的 RuntimeException, 該組件的MyCompany\Component\UnexpectedValueException, 或該組件的 MyCompany\Component\Exception. 這為捕捉你的類庫(kù)組件中的異常提供了極大的便利. 此外, 通過(guò)分析異常的類型, 我們也能看出某個(gè)異常的含義.  

總結(jié)

總而言之,本文旨在教大家, 創(chuàng)建和拋出異常的***標(biāo)準(zhǔn)做法, 即: 應(yīng)該多關(guān)注異常的類型, 少糾結(jié)異常的錯(cuò)誤消息。如果你有什么看法, 歡迎在這里留言, 或在 PHP 文檔網(wǎng)頁(yè), 亦或是上面給出鏈接的ZF2 wiki 留言。 

原文鏈接:http://www.oschina.net/translate/exception-best-practices-in-php-5-3

 

 
責(zé)任編輯:張偉 來(lái)源: oschina
相關(guān)推薦

2013-04-01 09:39:06

JavaJava異常

2015-03-16 16:16:15

JavaJava異常處理Java最佳實(shí)踐

2013-05-28 09:47:36

異常處理Javay異常

2018-02-06 09:05:25

Java異常處理代碼

2010-12-28 10:12:39

PHP

2016-12-13 10:13:18

PHPUTF-8實(shí)踐

2009-07-20 10:18:49

PHP 5.3命名空間

2009-03-23 10:53:00

PHP5.3新特性PHP5.3PHP5

2011-09-14 10:38:39

2014-09-01 09:57:11

Go產(chǎn)品環(huán)境最佳語(yǔ)言

2012-07-18 15:30:58

iOS交互原型

2009-11-26 10:31:55

配置IPS最佳實(shí)踐

2009-11-23 14:17:50

PHP 5.3閉包語(yǔ)法

2009-07-17 09:31:06

PHP 5.3命名空間

2015-09-15 16:01:40

混合IT私有云IT架構(gòu)

2011-08-18 11:05:21

jQuery

2023-07-21 01:12:30

Reactfalse?變量

2017-06-02 10:25:26

Java異常處理

2009-05-13 14:15:09

PHP 5.3閉包匿名函數(shù)

2023-09-13 08:00:00

JavaScript循環(huán)語(yǔ)句
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 91久久国产综合久久 | 久久精品国产精品青草 | 欧美日韩国产一区二区三区 | 亚洲成人久久久 | 中文字幕一区二区三区四区五区 | 99riav国产一区二区三区 | 国产成人在线视频免费观看 | 国产精品久久久久久久 | 免费看黄色片 | 99久久国产免费 | av香蕉 | 国产精品免费一区二区三区四区 | 亚洲一区二区在线 | 亚洲国产欧美日韩 | 精品视频999 | 91夜色在线观看 | 国产香蕉视频在线播放 | 精品国产一区二区三区成人影院 | 欧美日韩一区二区三区四区 | 91精品国产一区二区在线观看 | 久久久久久久综合色一本 | 九九热精品在线 | 欧美电影免费观看高清 | 亚洲精品一区二区 | 久久久视 | 高清视频一区二区三区 | 四虎最新 | 午夜精品一区二区三区在线观看 | 在线视频 亚洲 | 日韩免费高清视频 | 亚洲精品久久久久久国产精华液 | 日韩快播电影网 | 亚洲精品一二三 | 亚洲一区在线日韩在线深爱 | 三级黄色片在线播放 | 久久久久久亚洲 | 一级免费视频 | 久久久国产精品视频 | 日韩中文字幕免费在线观看 | 美女爽到呻吟久久久久 | 免费在线日韩 |