2010-04-06 2 views
10

Я запутался следующий код:Смущенный этим PHP Exception try..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"; 
    $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)?

Спасибо.

ответ

14

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

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

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

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

+0

Я просто хочу быть уверен, что мы на одной странице ... В принципе, он должен был добавить еще одну «попытку» после первого «улова», верно? Тогда, поскольку вся вещь встроена в большую попытку, он получит 3 набора исключений? По сути, он никогда не ловит второго исключения, потому что он никогда не пытается? – Anthony

+0

Если бы он, наоборот, изменил внешний 'catch' на« MyException »вместо« Exception », это поймало бы« MyException »« throw »? Является ли проблема, что его попытка запускает «throw» из «MyException», но поскольку попытка не была инициирована «try», «catch» никогда не происходит? Другими словами, «MyException» все еще существует, чтобы попасть в этот третий «улов»? – Anthony

+0

@ Anthony, re: Первый комментарий: Да, если бы он добавил третий уровень блока try, это было бы одним решением. Тем не менее, бит грязный. Я бы не стал характеризовать проблему, как у вас в последнем предложении, но это не так. – Oddthinking

5

Только потому, что в комментарии недостаточно. Подумайте о попытке ... уловить как цикл 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"; 
} 

распечатать последнее условие («\ $ а == 11»), так как условие уже встретил первого elseif. То же самое происходит с try ... catch. Если условие выполнено, оно не продолжает поиск новых условий в той же области.

0

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

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

1

Я не уверен, если следующее является законным («попробовать» ИНГ внутри водосборный блока), но дают ожидаемый результат:

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