Ola peepz,

Ik zit de laatste dagen wat te stoeien met exceptions, en ik vraag me nu af hoe jullie exceptions gebruiken. Gebruik je exceptions vooral om onverwachte gebeurtenissen op te vangen, of gebruik je ze ook als vervanging van if/else? Met dat laatste bedoel ik dit:

Zelf zou ik normaal gesproken dit doen:

<?php
if ($this->foo() === true) {
$this->bar();
} else {
$this->foobar();
}
?>
Nu zeggen een aantal van jullie dat het goed is om exceptions in je flow op te nemen. Is het dan de bedoeling dat je dit gaat doen?

<?php
try {
$this->foo();
$this->bar();
} catch (FooException $e) {
$this->foobar();
}
?>
Wat is nu in essentie het doel van Exceptions? Onverwachte dingen afhandelen (een database die gene verbinding kan maken, een bestand dat niet kan worden weggeschreven, een mailserver die plat ligt) of is het een moderne variant van if/else?
Ozzie je hebt 2 dingen

Errors
Hier gebruik je geen exceptions en meestal zijn dit kritieke fouten waarbij je systeem plat gaat.

Exceptions
Een Exception geeft aan dat er een probleem is voorgekomen maar niet zodanig dat de hele applicatie plat gaat.

Bijvoorbeeld

Ozzie voert een getal in ipv een letter. Het systeem gaat hierdoor niet plat maar jij wilt wel weten dat er een nummer ingevoerd is ipv een letter dus wat doe je dan?

<?php

throw new InvalidArgumentException('Gebruiker heeft een cijfertje ingevoerd!');
?>


>> Een Exception geeft aan dat er een probleem is voorgekomen maar niet zodanig dat de hele applicatie plat gaat.

Dat kan wel. Stel je kan geen verbinding maken met de database, dan kan het zijn dat je de rest van de site moet platgooien.

Maar ik bedoel het nog wat anders... WANNEER gebruik je exceptions. In welke situatie? Kun je het bijv. beschouwen als een alternatief voor het returnen van een boolean?

Voorbeeld:

Ik zou dit doen:

<?php
if ($this->user->isLoggedIn()) {
// user is ingelogd
// laat admin-panel zien
} else {
// toon het inlogscherm
}
?>
Is het dan de bedoeling dat je met exceptions dit gaat doen?

<?php
try {
$this->user->isLoggedIn();
// user is ingelogd
// laat admin-panel zien
catch (LoginException $e) {
// toon het inlogscherm
}
?>
Is dit de bedoeling hoe je tegenwoordig (met behulp van exceptions) moet programmeren?
Nee, exceptions zijn geen alternatief.

Ik ga het voor de laatste keer zeggen, aangezien ik het idee heb dat ik de afgelopen maand al 20x precies dezelfde vraag van jou heb beantwoord:

Een exception is vertaalt een uitzondering

Dus: Als je praat over een uitzondering van de functie.

Wat is dan een uitzondering? Iets wat niet zou moeten gebeuren wanneer de method in goede omstandigheden zou worden aangeroepen.

Onderscheid maken zoals Reshad doet, waarom dat? Ik zou graag het liefst alles in exceptions willen hebben, zoals het in OO hoort. Alleen dat PHP zijn errors niet als exceptions doet is een heel groot nadeel, geen voordeel.
Wouter, thanks. Ik word af en toe ook moe van mezelf momenteel moet ik zeggen. Het ene moment denk ik dat ik het doorheb, en dan kom ik er ineens weer niet uit.

Maar als ik jou dus goed begrijp... een exception is een uitzondering.

Functies zoals isLoggedIn(), isDirectory() enz. moeten dus gewoon een boolean teruggeven en geen exception?
Jup
Oké, dat is dan duidelijk. En nu heb ik dus iets waar ik al een tijdje m'n nek over breek. Misschien weet jij een goede oplossing.

Stel ik wil een cache directory verwijderen. Dan roep ik de deleteDir method van mijn filecacher aan. Deze functie maakt weer gebruik van de deleteDir method van het Filesystem. Het verwijderen zou (denk ik) mis kunnen gaan om 2 redenen, die volgens mij beiden een exception vereisen. Namelijk, of de directory die verwijderd moet worden bestaat niet, of de directory kan niet verwijderd worden (bijv. wegens verkeerde bestandsrechten).

Nu is mijn vraag... stel ik wil dus een cache dir verwijderen vanuit class Foo. Hoe moet ik dan omgaan met de exceptions? Stel dat het Filesystem (vanaf nu FS) de dir niet kan vinden, moet FS dan een specifieke class exception gooien of een algemene exception? Moet de deleteDir functie van de filecacher deze exception opvangen of juist niet en bijv. laten "opborrelen" totdat class Foo 'm opvangt? Of moet toch de filecacher deze exceptoin opvangen en dan een exception gooien. En zo ja, een algemene exception of een class specifieke exception enz.

Stel bijv. dat ik in class Foo een algemene Exception opvang, dan kan het zomaar zijn dat ik onbedoeld een exception opvang die niet uit de cacher class komt en die ik helemaal niet had moeten opvangen in class Foo. Kortom... hoe werkt het nu eigenlijk? Ik zou heel graag een voorbeeldje willen hoe in de praktijk zo'n voorbeeld als ik hierboven schetste eruit zou moeten zien. Hoe pak je dat op de juiste manier aan? Dus, class Foo wil een cache directory verwijderen en spreekt hiervoor de cacher class aan. De cacher class spreekt op zijn beurt de filesystem class aan. Er kunnen 2 exceptions plaatsvinden, namelijk de directory bestaat niet, of de directory bestaat wel maar kan niet verwijderd worden.

Wie kan een (klein) code-voorbeeld geven hoe ik op de juiste manier de juiste exceptions moet gooien, en hoe ik deze op de juiste plek omvang?

Alle hulp is welkom!
Je moet je exceptions opvangen als je dat wilt in je code. Wil je dat de exception gewoon gegooit wordt, doe dan niks, wil je iets speciaals doen met de exception in 1 bepaalde use-case, dan vang je hem op.

Dus stel je hebt je "directory bestaat niet" en "directory kan niet verwijderd worden" exceptions, dan kan je kiezen via je try catch block of je de globale Filesystem exception wilt opvangen, of dat je enkel de DirectoryDoesntExist of DirectyCantBeDeleted (uiteraard zijn dit fictieve, slechte classnamen) wilt opvangen.

Houd flexibiliteit in gedachten tijdens het programmeren!

Je denkt er teveel over na!
En waarom zou de filecacher zich bemoeien met het verwijderen van mappen? De filecacher praat alleen over data en plaatst dat zelf in bestandjes. Van buiten de klasse moet jij geeneens weten dat de filecacher cached via het filesysteem en niet bijv. de database.
Correct maar ik wil via de filecacher (of een andere cacher) bijv. in 1x alle cache data verwijderen. In het geval van een FILEcacher gebeurt dat door de cache directory te verwijderen. Voor het verwijderen van die directory maakt de FILEcacher gebruik van het filesystem. De functie heeft in de filecacher class deleteAll() en deze functie maakt dus gebruik van de deleteDir functie van het filesystem. Sorry voor de onduidelijkheid. Had ik even niet bij stilgestaan. Maar goed, dit is vooral een voorbeeld waarbij ik dus benieuwd ben hoe de verschillende klassen met elkaar om moeten gaan op het gebied van exceptions.
Oke, er bestaat dus een kans dat Filesystem::deleteDir een exception gooit. Fijn, de exception zal dus gegooid worden maar je het is best dat je die NIET opvangt in je filecacher class. Waarom niet? Misschien wil je op 1 moment wel de exception opvangen, maar dan misschien op de andere niet? Flexibiliteit!

Reageren