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?
maar dat komt dan toch uiteindelijk neer op één principe: opslaan/ophalen/verwijderen van specifieke data uit een voorgedefinieerde map en een bijhorende 'identifier'?
ik werk zelf vrij vaak met caches (omdat het gewoon nutteloze SQL-queries voorkomt die de bottleneck zijn voor de meeste applicaties) maar werk vanuit één class. die regelt voor mij het ophalen, opslaan en verwijderen (alles, specifieke reeksen op basis van de key of één enkele key) en werkt razendsnel.
[offtopic]ik krijg zelf altijd het gevoel dat op het moment dat je overal alles wilt gaan extenden/inheriten/implementeren de applicatie niet alleen bizar groot wordt (groter dan nodig zou moeten zijn) maar dat het ook qua snelheid z'n nadelen heeft. maar nou betrap ik mezelf erop dat dit onwijs offtopic gaat en dat een andere discussie is... excuus![/offtopic]
Nog even een vraagje... als je een exception niet opvangt en je hebt een exception handler functie ingesteld, gaat de code dan verder na het gooien van die exception die niet wordt opgevangen (maar dus wel in de exception handler functie terecht komt)? Ik kan het zelf even niet testen nu, vandaar mijn vraag.
Stel:
<?php
public function foo() {
throw new UncaughtException('ik word niet opgevangen');
echo 'hallo allemaal';
}
?>
Als we nu de functie foo aanroepen dan wordt de UncaughtException dus doorgestuurd naar de exception handler functie, maar wordt dan wel nog 'hallo allemaal' ge-echoot?
nee, bij het gooien van een exception stopt je script tot het moment dat je de exception opvangt. Aangezien de exception handler helemaal aan het eind van je script staat stopt dus gewoon je hele script.
Oei... dan had ik het verkeerd geinterpreteerd. Mijn idee was om sommige onschuldige exceptions op een hoger niveau te vangen en te loggen. Stel bijv. het cachen lukt niet en de cacher gooit een CacherException. Ik zat dan te denken, als ik die niet opvang en gewoon naar boven laat opborrelen naar de exception handler function, dan kan ie daar mooi gelogd worden. Maar dat werkt dus niet, want dan zou de applicatie direct stoppen.
Mijn gedachte was dus om onschuldige exceptions bewust te negeren en door de exception handler functie te laten loggen.
Stel nu, ik heb een object en ik wil dat object locken zodat de class properties niet kunnen worden gewijzigd. Stel ik lock het object, maar het object blijkt al gelockt te zijn. Het resultaat is natuurlijk hetzelfde. Het object is en blijft gelockt. Alleen het feit dat jij iets op slot wil zetten wat al op slot zit, klopt niet. Dus ik dacht, hé dat is een uitzondering, dus dan gooien we een exception. Het idee was om die exception dan ergens bovenin te loggen, maar de rest van de code gewoon door te laten gaan (er gebeurt immers niets ernstigs). Maar als ik jullie goed begrijp werkt dat niet. En dus zal ik de exception direct moeten opvangen. Maar overal waar je dan iets wil locken, krijg je dan dus zoiets:
<?php
try {
$object->lock();
catch (Exception $e) {
$this->logger->log('could not lock object');
}
?>
Is dat niet vreemd dat je dan een try/catch-blok gebruikt alleen om even iets te locken?
>> Over het algemeen laat je die exceptions juist wel opborrelen. Deze exceptions kom je al tegen in de dev. omgeving en ga je dan oplossen.
Hmmm, oké. Dus jij zou dan gewoon $object->lock(); doen en dit niet in een try/catch zetten?
Maar ik bedenk me... in het geval van lock zou dat inderdaad kunnen, dat je de exception laat opborrelen. Maar in het geval van een cacher die niet werkt moet je dat dus niet doen, want dan klapt je applicatie eruit. Correct?
(p.s. Blij dat jullie even antwoord geven, want ik was dus bijna de mist in gegaan...)
Het 2x locken van een object is een zogenaamde LogicException. Het is een exception die je bij het testen van je applicatie al door kan hebben en die als het ware door de compiler (als PHP er eentje had) gevonden wordt.
Het mislukken van een cacher is een RunTimeException. Zoiets is afhankelijk van dingen buiten de code om, namelijk het filesysteem of de database. Hierdoor kun je deze niet bij het compilen al vinden en deze moet je dus wel opvangen als je niet wilt dat de applicatie erdoor stopt.
Even nog een exception vraagje... ik ben even e.e.a. aan het ombouwen waardoor ik het nu niet zelf kan uittesten.
Als ik dit doe:
<?php
try {
throw new FooException('foo');
} catch (FooException $e) {
throw new BarException('bar');
} catch (BarException $e) {
echo 'hallo!';
}
?>
Verschijnt er nu 'hallo!' op het scherm? Anders gezegd, wordt de BarException die in de 1e catch wordt gegooid opgevangen door de 2e catch?