这个PHP异常混淆了try..catch嵌套

时间:2010-04-06 16:45:11

标签: php exception-handling

我对以下代码感到困惑:

class MyException extends Exception {}
class AnotherException extends MyException {}

class Foo {
  public function something() {
    print "throwing AnotherException\n";
    throw new AnotherException();
  }
  public function somethingElse() {
    print "throwing MyException\n";
    throw new MyException();
  }
}

$a = new Foo();

try {
  try {
    $a->something();    

  } catch(AnotherException $e) {
    print "caught AnotherException\n";
    $a->somethingElse();    
  } catch(MyException $e) {
    print "caught MyException\n";
  }
} catch(Exception $e) {
  print "caught Exception\n";
}

我希望这能输出:

throwing AnotherException
caught AnotherException
throwing MyException
caught MyException

但它输出:

throwing AnotherException
caught AnotherException
throwing MyException
caught Exception

有人可以解释为什么它“跳过”捕获(MyException $ e)?

感谢。

4 个答案:

答案 0 :(得分:16)

异常处理程序捕获由try块范围内的代码引发的异常。

$a->somethingElse()的调用不会发生在与跳过的异常处理程序关联的try块中。它发生在另一个catch子句中。

仅仅因为它看起来在物理上低于引发异常的行,不足以覆盖该代码。

缩进括号的样式选择使这不太清楚,恕我直言。前一个try块的close括号出现在与下一个catch相同的行上,即使它们是不相关的(好的,同级的)作用域。

答案 1 :(得分:6)

只是因为评论中没有足够的空间。想想try ... catch作为if ... else循环。您不会期望以下内容:

$a = 10;
if($a == 9)
    print "\$a == 9";
elseif($a == 10) {
    $a = 11;
    echo "now \$a == 11";
} elseif($a == 11) {
    echo "\$a == 11";
}

打印出最后一个条件(“\ $ a == 11”),因为第一个elseif已满足条件。 try ... catch也是如此。如果满足条件,则不会继续在同一范围内搜索新条件。

答案 2 :(得分:1)

我不确定以下是否合法("尝试在catch区块内),但确实给出了预期的输出:

class MyException extends Exception {}
class AnotherException extends MyException {}

class Foo {
  public function something() {
    print "throwing AnotherException\n";
    throw new AnotherException();
  }
  public function somethingElse() {
    print "throwing MyException\n";
    throw new MyException();
  }
}

$a = new Foo();

try {
   try {
      $a->something();
   } catch(AnotherException $e) {
       print "caught AnotherException\n";
       try{
          $a->somethingElse();
       } catch(MyException $e) {
          print "caught MyException\n";
       }
   }
} catch(Exception $e) {
  print "caught Exception\n";
}

提供输出:

throwing AnotherException
caught AnotherException
throwing MyException
caught MyException

答案 3 :(得分:0)

不确定这是否被认为是回答,但答案甚至比这里提出的更简单。对于每次尝试,只能触发一个捕获块,它始终是最具体的一个。

在这种情况下,AnotherException由内部try / catch的第一个catch块抛出并处理,因此第二个catch块不会处理它。 catch块中抛出的新异常由外部try / catch处理。