try/catch versus die

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Thomas van den Heuvel

Thomas van den Heuvel

17/02/2015 16:15:19
Quote Anchor link
Stel, je applicatie gebruikt een database class (of andere functionaliteit).

Bij het aanmaken van de objecten die je in je applicatie gebruikt (dus kort door de bocht: het aanroepen van de __construct() methoden) wordt bij het database-object informatie gebruikt uit een externe configuratie-bron (een object, een array, een bestand, doet er eigenlijk niet toe).

Nu zit er een fout in de parameters voor het maken van een verbinding met de database.

Als het maken van een connectie mislukt staak ik de hele applicatie met die() (met een duidelijke omschrijving van het euvel, uiteraard).

Dit omdat dit een configuratie-fout is die handmatig moet worden verbeterd. Daarnaast omdat de rest van de applicatie valt of staat met het correct werken van de database, het heeft simpelweg geen zin om proberen te "herstellen" van deze situatie omdat 'ie in wezen gewoon "kapot" is door de foutieve configuratie.

Dit doe ik ook bij het aanmaken van de andere objecten - de applicatie is in wezen bezig met initialisatie. Als er daar iets mis gaat dan kan een verdere correcte werking niet gegarandeerd worden.

Ik noemde al een aantal argumenten voor het gebruiken van die() in plaats van een try/catch blok. Ik gebruik overigens geen PDO, het is dan wel verstandig om alles in een try-catch blok te zetten ;-).

Mijn vraag: wat zijn de argumenten voor (of tegen) het gebruik van die/exit versus try-catch in dit stadium van je applicatie onder deze omstandigheden (foutieve configuratie)?

---

Het is eigenlijk een beetje een kip-ei situatie in mijn geval. Bezoekers van de site (applicatie) krijgen een nette fout-pagina te zien wanneer er iets misgaat ("runtime" errors worden wel gethrowd en gevangen). Maar alle pagina's / content komen uit de database. Als ik geen database heb, kan ik ook geen pagina('s) tonen, dus ook geen foutpagina. Je ziet mijn dilemma :).
 
PHP hulp

PHP hulp

26/12/2024 10:35:21
 

17/02/2015 16:37:54
Quote Anchor link
Ik zelf opper altijd voor een try/catch.

Je kan namelijk in een try/catch een exception catchen en netjes afhandelen.

Bijvoorbeeld;

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
try {
    $dir = new \DirectoryContainer($config['directory'], new DirectoryFilter());
}
catch (Exception $e) {
    die($twig->render('errors/general-error.html.twig', array('errormessage' => $e)));
}

?>


Ook hier gebruik ik een die() maar ik krijg wel meer info uit het Exception object.
Het is dynamischer vindt ik zelf.
 
Thomas van den Heuvel

Thomas van den Heuvel

17/02/2015 16:53:52
Quote Anchor link
Om eerder genoemde reden (de content zit in mijn database) kan ik de aanpak die jij hanteert niet gebruiken.

Als mijn applicatie eenmaal correct en volledig is geïnitialiseerd schakel ik over op try-catch zodat ik ook mijn exceptions netjes kan afhandelen.

Ik maak onderscheid tussen wat "developers" zien en wat "gewone bezoekers" te zien krijgen, ik ga een bezoeker niet lastig vallen met een cryptische foutmelding. Ik krijg (als developer) de foutmelding rauw te zien (die() met exception boodschap, zoals jij ook doet), bezoekers krijgen een nette foutpagina voorgeschoteld die gegenereerd wordt met behulp van informatie uit de database.

De opbouw is in grote lijnen als volgt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
// laden van benodigde objecten / init
// ...

try {
    // uitvoeren applicatie acties
    // ...

} catch (Exception $e) {
    // log error
    // ...

    if (<developer check>) {
        die(<boodschap met details exception>);
    }
else {
        try {
            // probeer de error pagina te laden, maar ook dit kan foutgaan
            // omdat er ergens in een pagina-element dezelfde/een andere fout zit
            // dit is in feite het opnieuw uitvoeren van applicatie acties
            // ...

        } catch (Exception $e) {
            // log error
            // ...
            // ik heb mijn best gedaan, maar kan hier verder niets meer mee/aan doen

            die('[error] something seriously broke');
        }
    }
}

?>


EDIT: met als "verschil" dus dat in het init-deel (regel 3) mogelijk de applicatie stopgezet wordt als er configuratie-fouten zijn.
Gewijzigd op 17/02/2015 16:56:41 door Thomas van den Heuvel
 
Ward van der Put
Moderator

Ward van der Put

17/02/2015 17:09:51
Quote Anchor link
>> Als ik geen database heb, kan ik ook geen pagina('s) tonen, dus ook geen foutpagina. Je ziet mijn dilemma :).

Dat kan wel als je een ErrorDocument instelt in bijvoorbeeld .htaccess en je de reeks exceptions vervolgens laat eindigen in een nette HTTP-fout (meestal 500 en bij een overvraagde databaseserver eventueel een 503). Helaas moet dat dan meestal wel een statische HTML-pagina zijn.

Als je de logica van de SPL-exceptions volgt of nabouwt, maak je ook een onderscheid tussen logic exceptions en runtime exceptions.
 
Thomas van den Heuvel

Thomas van den Heuvel

17/02/2015 17:25:53
Quote Anchor link
En onder welk (Logic?)Exception type zou dan een niet-kloppende configuratie-waarde moeten vallen (type is niet fout (string), waarden-domein kun je moeilijk vangen, dit kan van alles zijn, iets anders?)?

Volgens mij dekken beide Exception (sub)types niet echt de lading.

Statische HTML-pagina... tsja. De error pagina zou editbaar moeten zijn.

Wat is er mis mee om een configuratie-fout als fatal error te behandelen?
 
Ward van der Put
Moderator

Ward van der Put

17/02/2015 17:40:53
Quote Anchor link
Het lijkt me een glijdende schaal met meerdere keuzen en oplossingen. Zonder mailserver kun je (even) niet mailen, maar moet een complete applicatie daardoor onderuit gaan? Zonder toegang tot de databaseserver heb je ook (even) geen data, maar moet een site dan helemaal plat gaan?

Of een configuratiefout een fatal error is, is ook niet zomaar te zeggen. Alles is configureerbaar te maken, maar niet elke configuratiefout is dus fataal.
 
Thomas van den Heuvel

Thomas van den Heuvel

17/02/2015 17:53:02
Quote Anchor link
In mijn opzet zie ik niet echt een andere oplossing. Ik probeer dit probleem wat verder te verkennen door het hier voor te leggen, maar ik heb nog geen doorslaggevende argumenten gehoord waarom mijn opzet fout zou zijn.

Maar de algemene aanpak is dus een beetje: staak de applicatie als het opzetten van een of meer objecten niet lukt lijkt mij niet verkeerd?

Vergelijk het met de lancering van een raket: als een van de stuwraketten niet vuurt, wil jij de lancering dan toch voortzetten? Ik kan wel een redelijke voorspelling doen waar dat dan in uitmondt.

Exceptions zijn ook niet altijd de oplossing. Als je weet dat een correcte operatie van je applicatie op enig moment niet haalbaar is kun je beter direct stoppen lijkt mij. Te meer als er overduidelijke mankementen zijn.

"Onze autoband staat plat, maar laten we toch op skivakantie gaan."

:)

EDIT:
Quote:
Zonder mailserver kun je (even) niet mailen, maar moet een complete applicatie daardoor onderuit gaan? Zonder toegang tot de databaseserver heb je ook (even) geen data, maar moet een site dan helemaal plat gaan?

Leuk voorbeeld :). Het eerste probleem kun je ondervangen door berichten tijdelijk op te slaan in je database, en het verzenden later nogmaals te proberen. Dat wordt wel een beetje lastig als je database eruit ligt ;-). Tenzij je een fallback hiervoor hebt via tekst-bestanden :). Maar wat nu als je diskruimte vol is? :) etc.

Soms kun je problemen niet voor je uitschuiven, of is het onverstandig om dit te doen.
Gewijzigd op 17/02/2015 18:09:48 door Thomas van den Heuvel
 
Ward van der Put
Moderator

Ward van der Put

17/02/2015 18:10:39
Quote Anchor link
Specifiek voor databaseverbindingen gebruik ik wel een andere oplossing: nog een keer proberen.

Bij schaarse resources heb je namelijk altijd het probleem dat de ene emmer net iets eerder vol/leeg is dan de andere emmer.
 
Wouter J

Wouter J

17/02/2015 18:52:47
Quote Anchor link
Exceptions sluiten die niet uit, dat is juist het mooie en het grote verschil met het gebruik van die. Het gebruik van die heeft namelijk maar 1 zijde: Stop en nu meteen!

Met exceptions koppel je de fout los van de applicatie. De database connector class kan niet connecten, resultaat: CannotConnectException. De connector stopt, maar wat er verder gebeurd ligt buiten het bereik van deze database connector en dat hoort ook zo. De applicatie kan een exception handler hebben die bij een CannotConnectException die() uitvoert, maar de class die de connector aanroept zou ook kunnen beslissen om de CannotConnectException op te vangen en in plaats daarvan de cache als fallback te gebruiken. In weer een ander scenario zou de class die de connector aanroept nog een keer de connector aanroepen, om te kijken of het dan wel werkt.

Dat is het mooie en grote voordeel van exceptions: Een scheiding tussen error en afhandeling. Precies in de lijn met de OO gedachte.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.