Confused этим PHP Исключение try..catch nesting

Меня смущает следующий код:

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

Может ли кто-нибудь объяснить, почему он "пропускает" catch (MyException $e)?

Спасибо.

Ответ 1

Обработчики исключений исключений, вызванные кодом внутри области действия блока try.

Вызов $a->somethingElse() не выполняется в блоке try, связанном с пропущенным обработчиком исключений. Это происходит в другом предложении catch.

Просто потому, что он физически отображается под строкой, которая вызывает исключение, недостаточно, чтобы закрыть этот код.

Выбор стиля отступных брекетов делает это менее ясным, ИМХО. Закрывающая скобка для предыдущего блока try появляется в той же строке, что и следующий улов, хотя они не связаны между собой (ну, родственные) области.

Ответ 2

Только потому, что в комментарии недостаточно места для этого. Подумайте о попытке... уловить как цикл 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. Если условие выполнено, оно не продолжает поиск новых условий в той же области.

Ответ 3

Я не уверен, что следующее правовое ( "попробуйте" внутри блока 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

Ответ 4

Не уверен, что это ответ считается или нет, но ответ еще проще, чем то, что было здесь задано. Для каждой попытки может быть запущен только один блок catch, и он всегда будет наиболее конкретным.

В этом случае AnotherException вызывается и обрабатывается первым блоком catch внутреннего try/catch, поэтому он не будет обрабатываться вторым блоком catch. Новое исключение, брошенное в блок catch, обрабатывается внешним try/catch.