In diesem Artikel werden hauptsächlich die Methoden der Ausnahmebehandlung in PHP vorgestellt. Ich hoffe, dass er für alle hilfreich ist.
Jede neue Funktion, die der PHP-Laufzeitumgebung hinzugefügt wird, erzeugt eine exponentielle Zufallszahl, sodass Entwickler diese neue Funktion nutzen und sogar missbrauchen können. Allerdings gelangten die Entwickler erst zu einem Konsens, als einige gute und schlechte Anwendungsfälle auftauchten. Wenn diese neuen Fälle auftauchen, können wir endlich erkennen, welcher Ansatz der beste oder der schlechteste ist.
Die Ausnahmebehandlung ist in der Tat keineswegs eine neue Funktion in PHP. In diesem Artikel werden wir jedoch zwei neue Funktionen besprechen, die auf der Ausnahmebehandlung in PHP 5.3 basieren. Bei der ersten handelt es sich um verschachtelte Ausnahmen und bei der zweiten um eine Reihe neuer Ausnahmetypen, die durch SPL (eine Kernerweiterung des aktuellen PHP-Betriebsmechanismus) erweitert werden. Für diese beiden neuen Funktionen finden Sie in diesem Buch Best Practices, die es wert sind, ausführlich studiert zu werden.
Besonderer Hinweis: Einige dieser Funktionen sind bereits in PHP-Versionen vor 5.3 vorhanden oder können zumindest in Versionen vor 5.3 implementiert werden. Wenn in diesem Artikel PHP 5.3 erwähnt wird, handelt es sich nicht unbedingt um eine PHP-Laufzeitumgebung Es bedeutet vielmehr, dass Codebasen und Projekte PHP 5.3 als Mindestversion übernehmen, aber auch für alle Best Practices, die während dieser neuen Entwicklungsphase entstehen. Hervorgehoben werden die „2.0“-Versuche bestimmter Projekte wie Zend Framework, Symfony, Doctrine und PEAR.
Hintergrund
Nur PHP 5.2 Eine Ausnahmeklasse Exception. Gemäß den Zend Framework/PEAR-Entwicklungsstandards ist diese Klasse die Basisklasse für alle Ausnahmeklassen in Ihrer Bibliothek. Wenn Sie eine Bibliothek mit dem Namen MyCompany gemäß den Zend Framework-/PEAR-Standards erstellen, beginnen alle Codedateien in der Bibliothek mit MyCompany_. Wenn Sie Ihre eigene Ausnahmebasisklasse für die Bibliothek erstellen möchten: MyCompany_Exception, verwenden Sie diese Klasse, um Exception zu erben, und dann erbt die Komponente (Komponente) diese Ausnahmeklasse und löst sie aus. Wenn Sie beispielsweise über eine Komponente „MyCompany_Foo“ verfügen, können Sie eine Ausnahmebasisklasse „MyCompany_Foo_Exception“ zur Verwendung innerhalb der Komponente erstellen. Diese Ausnahmen können durch Code abgefangen werden, der MyCompany_Foo_Exception, MyCompany_Exception oder Exception abfängt. Für anderen Code in der Bibliothek, der diese Komponente verwendet, handelt es sich um eine dreistufige Ausnahme (oder mehr, je nachdem, wie viele Unterklassen MyCompany_Foo_Exception hat), und sie können diese Ausnahmen nach eigenem Ermessen behandeln.
In PHP5 unterstützt die grundlegende Ausnahmeklasse bereits Verschachtelungsfunktionen. Was ist Verschachtelung? Unter Verschachtelung versteht man die Fähigkeit, eine bestimmte Ausnahme oder ein neues Ausnahmeobjekt abzufangen, das unter Bezugnahme auf die ursprüngliche Ausnahme erstellt wurde. Dadurch kann sich das Aufruferattribut auf die beiden Ausnahmeklassen auswirken, die in der Overhead-Bibliothek der öffentlicheren Typen erscheinen, und natürlich auf die Ausnahmeklasse mit dem ursprünglichen Ausnahmeverhalten.
Warum sind diese Funktionen nützlich? Oftmals ist es am effizientesten, Ausnahmen Ihres eigenen Typs auszulösen, indem Sie anderen Code verwenden. Bei diesem Code kann es sich um Code aus einer Codebibliothek eines Drittanbieters handeln, der einige anpassbarere Funktionen bereitstellt, die mithilfe des Adaptermusters gekapselt sind, oder um einfachen Code, der einige PHP-Erweiterungen zum Auslösen von Ausnahmen verwendet.
In der Komponente Zend_Db wird beispielsweise das Adaptermuster verwendet, um bestimmte PHP-Erweiterungen zu kapseln und eine Datenbankabstraktionsschicht zu erstellen. In einem Adapter kapselt Zend_Db PDO und PDO löst eine eigene Ausnahme aus PDOException, Zend_Db muss diese PDO-spezifischen Ausnahmen abfangen und sie als vorhersehbaren und bekannten Typ von Zend_Db_Exception erneut auslösen. Dies gibt dem Entwickler die Garantie, dass Zend_Db immer Ausnahmen vom Typ Zend_Db_Exception auslöst (und daher abgefangen werden kann). Sie haben bei Bedarf auch Zugriff auf die ursprünglich ausgelöste PDOException.
Das folgende Beispiel zeigt, wie ein fiktiver Datenbankadapter eingebettete Ausnahmen implementieren könnte:
class MyCompany_Database { /** * @var PDO object setup during construction */ protected $_pdoResource = null; /** * @throws MyCompany_Database_Exception * @return int */ public function executeQuery($sql) { try { $numRows = $this->_pdoResource->exec($sql); } catch (PDOException $e) { throw new MyCompany_Database_Exception('Query was unexecutable', null, $e); } return $numRows; } }
Um eingebettete Ausnahmen verwenden zu können, müssen Sie Folgendes tun So rufen Sie die getPrevious()-Methode der abgefangenen Ausnahme auf:
// $sql and $connectionParameters assumed try { $db = new MyCompany_Database('PDO', $connectionParams); $db->executeQuery($sql); } catch (MyCompany_Database_Exception $e) { echo 'General Error: ' . $e->getMessage() . "\n"; $pdoException = $e->getPrevious(); echo 'PDO Specific error: ' . $pdoException->getMessage() . "\n"; }
Die zuletzt implementierten PHP-Erweiterungen verfügen beide über OO-Schnittstellen (Object Oriented). Daher neigen diese APIs dazu, Ausnahmen auszulösen, anstatt mit Fehlern zu enden. Zu den Erweiterungen in PHP, die Ausnahmen auslösen können, gehören PDO, DOM, Mysqli, Phar, Soap und SQLite.
Neue Funktionen: Neue Kernausnahmetypen
In der PHP 5.3-Entwicklung Wir haben einige interessante neue Ausnahmetypen vorgestellt. Diese Ausnahmen gab es in PHP 5.2. Sie sind in der SPL-Erweiterung implementiert und im Handbuch aufgeführt (hier). Da diese neuen Ausnahmetypen Teil des PHP-Kerns und auch Teil von SPL sind, können sie von jedem verwendet werden, der Code mit PHP 5.3 (und höher) ausführt. Auch wenn es beim Schreiben von Code auf Anwendungsebene nicht so wichtig erscheint, wird die Verwendung dieser neuen Ausnahmetypen wichtiger, wenn wir Codebibliotheken schreiben oder verwenden
那么为什么新异常是普通类型?以前,开发者试图通过在异常消息提醒中放入更多的内容来赋予异常更多的含义。虽然这样做是可行的,但是它有几个缺点。一是你无法捕获基于消息的异常。这可是一个问题,如果你知道一组代码是同样的异常类型与不同的提示消息对应不同异常情况下,处理起来的难度将相当的大。例如,一个认证类,在对$auth->authenticate();;它抛出异常的相同类型的(假设是异常),但不同的消息对应两个具体的故障:产生故障原因是认证服务器不能达到但是相同的异常类型却提示失败的验证消息不同。在这种情况下(注意,使用异常可能不是处理认证响应最好的方式),这将需要用字符串来解析消息从而处理这两种不同的情况。
这个问题的解决办法显然是通过某种方式对异常进行编码,这样就可以在需要辨别如何对这种异常环境做出反应的时候能够更加容易的查询到。第一个反应库是使用异常基类的$code属性。另一个是通过创建可以被抛出且能描述自身行为的子类或者新的异常类。这两种方法具有相同的明显的缺点。两者都没有呈现出想这样的最好的例子。两者都不被认为是一个标准,因此每个试图复制这两种解决方案的项目都会有小的变化,这就迫使使用这需要回到文档以了解所创建的库中已经有的具体解决方案。现在通过使用SPL的新的类型方法,也称作php标准库;开发者就可以以同样的方式在他们的项目中,并且复用这些项目的新的最佳的方法已经出现。
第二个缺点是使用详细信息的做法使得理解这些异常情况对那些非英语或英语能力有限的开发者来说十分困难。这可能会使的开发者在试图理解异常信息的含义的过程十分的缓慢。许多开发者也会写关于异常的文章,因为还未出现一个统一的整合过的标准所要有同这些开发者数量相同的不同的版本来描述异常消息所描述的情况。
所以我如何去使用它们,就用这些让人无语的密密麻麻的细节描述?
现在在SPL中有总共13个新的异常类型。其中两个可被视为基类:逻辑异常和运行时异常;两种都继承php异常类。其余的方法在逻辑上可以被拆分为3组:动态调用组,逻辑组和运行时组。
动态调用组包含异常 BadFunctionCallException和BadMethodCallException,BadMethodCallException是BadFunctionCallException(LogicException的子类)的子类,这意味着这些异常可以被其直接类型(译者注:就是异常自身的类型,大家都知道异常有很多种)、LogicException,或者Exception抓到(译者注:就是catch)你应该在什么时候使用这些?通常,你应该在由一个无法处理的__call()方法产生的情况,或者回调无法不是一个有效的函数(简单说,当某些东西并非is_callable())时使用。
例如:
// OO variant class Foo { public function __call($method, $args) { switch ($method) { case 'doBar': /* ... */ break; default: throw new BadMethodCallException('Method ' . $method . ' is not callable by this object'); } } } // procedural variant function foo($bar, $baz) { $func = 'do' . $baz; if (!is_callable($func)) { 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异常。
要理解得更好,我们来看看这个概念在代码中的运用:
class Foo { protected $number = 0; protected $bar = null; public function __construct($options) { /** 本方法抛出LogicException异常 **/ } public function setNumber($number) { /** 本方法抛出LogicException异常 **/ } public function setBar(Bar $bar) { /** 本方法抛出LogicException异常 **/ } public function doSomething($differentNumber) { if ($differentNumber != $expectedCondition) { /** 在这里,抛出LogicException异常 **/ } /** * 在这里,本方法抛出RuntimeException异常 */ } }
现在理解了这一概念,那么,对代码库的使用者来说,这是做什么的呢?使用者可以随时确定对象的异常状态,他们可以用异常的具体的类型来捕获(catch)异常,例如InvalidArgumentException或LengthException,至少也是LogicException。通过这种级别的精度调整,和类型的多样,他们可以用LogicException捕获最小的异常,但也可以通过实际的异常类型获得更好的理解。同样的概念也适用于运行时的异常,可以抛出更多的特定类型的异常,并且不论是特定或非特定类型的异常,都可以被捕获(catch)。它可以给使用者提供更详细的情况和精确度。
下面是一个关于SPL异常的表,您可能会有兴趣
类库代码中的最佳实践
PHP 5.3 带来了新的异常类型, 同时也带给我们新的最佳实践. 除了将某些特定的异常(如: InvalidArgumentException, RuntimeException)标准化外, 捕捉组件级的异常, 也很重要. 关于这方面, ZF2 wiki 和 PEAR2 wiki 上面有深入的探讨.
简而言之, 除了上面提到的各种最佳实践, 我们还应该用 Marker Interface 来创建一个组件级的异常基类. 通过创建组件级的 Marker Interface, 用在组件内部的异常既能继承 SPL 的异常类型, 也能在运行时被各种代码捕捉. 我们来看下列代码:
// usage of bracket syntax for brevity namespace MyCompany\Component { interface Exception {} class UnexpectedValueException extends \UnexpectedValueException implements Exception {} class Component { public static function doSomething() { if ($somethingExceptionalHappens) { throw new UnexpectedValueException('Something bad happened'); } } } }
如果调用上面代码中的 MyCompany\Component\Component::doSomething() 函数, doSomething() 抛出的异常可以当作下列异常类型捕捉: PHP 的 Exception, SPL 的 UnexpectedValueException, SPL 的 RuntimeException, 该组件的MyCompany\Component\UnexpectedValueException, 或该组件的 MyCompany\Component\Exception. 这为捕捉你的类库组件中的异常提供了极大的便利. 此外, 通过分析异常的类型, 我们也能看出某个异常的含义.
总结:以上就是本篇文的全部内容,希望能对大家的学习有所帮助。
相关推荐:
Das obige ist der detaillierte Inhalt vonAusnahmebehandlungsmethoden in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!