Ho intenzione di darvi una discussione molto insolita sul controllo degli errori.
Ho costruito un ottimo gestore degli errori in una lingua anni fa e, sebbene alcuni dei nomi siano cambiati, i principi dell'elaborazione degli errori sono gli stessi oggi. Avevo un sistema operativo multi-tasking personalizzato e dovevo essere in grado di recuperare da errori di dati a tutti i livelli senza perdite di memoria, crescita dello stack o arresti anomali. Quindi quello che segue è la mia comprensione di come devono funzionare gli errori e le eccezioni e come differiscono. Dirò solo che non ho una comprensione di come funzionano gli interni di try catch, quindi immagino in una certa misura.
La prima cosa che accade sotto le coperte per l'elaborazione degli errori è passare da uno stato del programma a un altro. Come si fa? Ci arrivo io.
Storicamente, gli errori sono più vecchi e più semplici e le eccezioni sono più recenti e un po 'più complesse e capaci. Gli errori funzionano bene fino a quando non è necessario riempirli di bolle, il che equivale a passare un problema difficile al tuo supervisore.
Gli errori possono essere numeri, come numeri di errore e talvolta con una o più stringhe associate. Ad esempio, se si verifica un errore di lettura del file, potresti essere in grado di segnalare di cosa si tratta e possibilmente fallire. (Hay, è un passo avanti rispetto allo schianto come ai vecchi tempi.)
Quello che non viene detto spesso sulle eccezioni è che le eccezioni sono oggetti stratificati su uno speciale stack di eccezioni. È come uno stack di ritorno per il flusso del programma, ma mantiene uno stato di ritorno solo per i tentativi di errore e le catture. (Li chiamavo ePush ed ePop, e? Abort era un lancio condizionale che avrebbe ePop e avrebbe recuperato a quel livello, mentre Abort era un dado completo o un'uscita.)
In fondo allo stack ci sono le informazioni sul chiamante iniziale, l'oggetto che conosce lo stato in cui è stato avviato il tentativo esterno, che spesso è quando è stato avviato il programma. Inoltre, o il livello successivo della pila, con in alto i figli e in basso i genitori, è l'oggetto eccezione del successivo blocco try / catch interno.
Se metti una prova all'interno di una prova, stai impilando la prova interna sopra quella esterna. Quando si verifica un errore nel tentativo interno e il catch interno non può gestirlo o l'errore viene lanciato al tentativo esterno, il controllo viene passato al blocco catch esterno (oggetto) per vedere se è in grado di gestire l'errore, ad es. il tuo supervisore.
Quindi ciò che fa questo stack di errori è essere in grado di contrassegnare e ripristinare il flusso del programma e lo stato del sistema, in altre parole, consente a un programma di non bloccare lo stack di ritorno e rovinare le cose per gli altri (dati) quando le cose vanno male. Quindi salva anche lo stato di qualsiasi altra risorsa come i pool di allocazione della memoria e quindi può ripulirli quando il rilevamento è terminato. In generale questa può essere una cosa molto complicata ed è per questo che la gestione delle eccezioni è spesso lenta. In generale un bel po 'di stato deve entrare in questi blocchi di eccezioni.
Quindi una sorta di blocco try / catch imposta uno stato a cui poter tornare se tutto il resto viene incasinato. È come un genitore. Quando le nostre vite si incasinano, possiamo ricadere in grembo ai nostri genitori e loro rimetteranno tutto a posto.
Spero di non averti deluso.
Errors are generally unrecoverable
<- in realtà, questo non è proprio vero.E_ERROR
eE_PARSE
sono i due errori irreversibili più comuni (ce ne sono un paio di altri) ma la stragrande maggioranza degli errori che vedrai in dev sono recuperabili (E_NOTICE
,E_WARNING
et al). Sfortunatamente la gestione degli errori di PHP è un disastro completo: tutti i tipi di cose innescano errori inutilmente (la stragrande maggioranza delle funzioni del file system, per esempio). In generale le eccezioni sono "il modo OOP", ma sfortunatamente alcune delle API OOP native di PHP utilizzano errori invece di eccezioni :-(