2010-04-06 14 views
10

estoy confundido por el siguiente código:confundido por esta excepción PHP try..catch anidación

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"; 
} 

Yo esperaría que esto de salida:

throwing AnotherException 
caught AnotherException 
throwing MyException 
caught MyException 

Pero en vez de eso da salida:

throwing AnotherException 
caught AnotherException 
throwing MyException 
caught Exception 

¿Alguien podría explicar por qué se "salta" la captura (MyException $ e)?

Gracias.

Respuesta

14

Los manejadores de excepciones capturan la excepción provocada por el código dentro del alcance de su bloque try.

La llamada a $a->somethingElse() NO ocurre dentro del bloque try asociado con el manejador de excepción omitido. Ocurre dentro de otra cláusula catch.

El hecho de que aparezca físicamente debajo de la línea que genera la excepción no es suficiente para que cubra ese código.

La opción de estilo de las correas de sangrado lo hace menos claro, en mi humilde opinión. El corsé cercano para el bloque try anterior aparece en la misma línea que el siguiente catch, aunque sean ámbitos no relacionados (bueno, hermanos).

+0

sólo quiero estar Seguro que estamos en la misma página ... Básicamente debería haber agregado otro 'try' después del primer' catch', ¿verdad? Entonces, como todo está incrustado en el intento mayor, ¿obtendría 3 conjuntos de excepciones? Básicamente, nunca atrapa la segunda excepción porque nunca lo intenta. – Anthony

+0

Si, como alternativa, hubiera cambiado el 'catch' externo a" MyException "en lugar de a" Exception ", ¿hubiera capturado el 'throw' MyException? ¿El problema es que su intento desencadena el 'throw' de" MyException "pero debido a que el intento no fue iniciado por un' try', el 'catch' nunca ocurre? En otras palabras, ¿está "MyException" todavía por capturar ese tercer "catch"? – Anthony

+0

@Anthony, re: Primer comentario: Sí, si agregó un tercer nivel de bloqueo de prueba, esa sería una solución. Un poco desordenado sin embargo. No elegiría caracterizar el problema como lo hizo en su última oración, pero no está * mal *. – Oddthinking

5

Solo porque no hay espacio suficiente para esto en un comentario. Piense en el intento ... atrapar como un bucle if ... else. No se podía esperar lo siguiente:

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

para imprimir la última condición ("\ $ a == 11"), debido a la condición ya fue recibido por el primer elseif. Lo mismo es cierto con el try ... catch. Si se cumple la condición, no continúa buscando nuevas condiciones en el mismo ámbito.

0

No estoy seguro si esto se ha considerado como respondido o no, pero la respuesta es incluso más simple que lo que se ha planteado aquí. Para cada intento, solo se puede activar UN bloque de captura y siempre será el más específico aplicable.

En este caso, AnotherException es arrojado y manejado por el primer bloque catch del try/catch interno, por lo que no será manejado por el segundo bloque catch. La nueva excepción lanzada en el bloque catch se maneja mediante try/catch externo.

1

No estoy seguro de si sigue es legal ("tratar" ing dentro de un bloque catch), pero sí da resultado esperado:

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"; 
} 

Da salida:

throwing AnotherException 
caught AnotherException 
throwing MyException 
caught MyException