L的新的类型方法,也称作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?来创建一个组件级的异常基类.?通过创建组件级的 Mark