2010-04-06 17 views
10

Sono confuso con il codice seguente:Confuso da questa eccezione PHP try..catch nidificazione

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

mi si aspetterebbe che questo output:

throwing AnotherException 
caught AnotherException 
throwing MyException 
caught MyException 

Ma invece uscite:

throwing AnotherException 
caught AnotherException 
throwing MyException 
caught Exception 

Qualcuno potrebbe spiegare il motivo per cui "ignora" il rilevamento (MyException $ e)?

Grazie.

risposta

14

I gestori di eccezioni catturano l'eccezione generata dal codice all'interno dell'ambito del blocco try.

La chiamata a $a->somethingElse() NON si verifica all'interno del blocco try associato al gestore di eccezioni ignorate. Si verifica all'interno di un'altra clausola di cattura.

Proprio perché appare fisicamente al di sotto della linea che solleva l'eccezione non è sufficiente a far sì che copra quel codice.

La scelta dello stile di parentesi graffe rende questo meno chiaro, IMHO. La parentesi graffa per il blocco try precedente viene visualizzata sulla stessa riga del prossimo catch, anche se sono ambiti non correlati (well, sibling).

+0

voglio solo essere certo siamo sulla stessa pagina ... In sostanza avrebbe dovuto aggiungere un altro 'try' dopo il primo' catch', giusto? Quindi, poiché l'intera cosa è incorporata nella prova più ampia, otterrebbe 3 serie di eccezioni? Essenzialmente non cattura mai la seconda eccezione perché non ci prova mai? – Anthony

+0

Se, alternativamente, avesse cambiato il 'catch' esterno in" MyException "invece di" Exception ", questo avrebbe catturato il" lancio "di" MyException "? Il problema è che il suo tentativo innesca il lancio di "MyException" ma poiché il tentativo non è stato avviato da un 'try', il' catch' non succede mai? In altre parole, "MyException" è ancora là fuori per essere catturato da quel terzo "catch"? – Anthony

+0

@Anthony, re: Primo commento: Sì, se ha aggiunto un terzo livello di blocco try che sarebbe una soluzione. Un po 'disordinato però. Non sceglierei di caratterizzare il problema come nella tua ultima frase, ma non è * sbagliato *. – Oddthinking

5

Solo perché non c'è spazio sufficiente per questo in un commento. Pensa al tentativo ... prendi un ciclo if ... else. Non ci si aspetterebbe il seguente:

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

per stampare l'ultima condizione ("\ $ a == 11"), perché la condizione era già incontrato dal primo elseif. Lo stesso vale per il try ... catch. Se la condizione è soddisfatta, non continua la ricerca di nuove condizioni nello stesso ambito.

0

Non sicuro se questo è stato considerato una risposta o meno, ma la risposta è ancora più semplice di quanto è stato posto qui. Per ogni tentativo, può essere attivato solo un blocco di cattura e sarà sempre il più specifico applicabile.

In questo caso, AnotherException viene lanciata e gestita dal primo blocco catch del try/catch interno, quindi non verrà gestita dal secondo blocco catch. La nuova eccezione generata nel blocco catch viene gestita dal try/catch esterno.

1

Io non sono sicuro se segue è legale ("provare" ing all'interno di un blocco catch), ma dà output previsto:

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

Dà uscita:

throwing AnotherException 
caught AnotherException 
throwing MyException 
caught MyException