Try en Catch

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Jorn Reed

Jorn Reed

01/07/2021 10:00:49
Quote Anchor link
Hallo iedereen!

Ik ben nou al een hele tijd bezig met het developen van PHP applicaties.
Zo ben ik nu bijvoorbeeld bezig met een applicatie in Laravel, dat lukt me aardig, zo werk ik nu dus ook met een Laravel package die api data kan ophalen met een Http class. Nu is mij de vraag, het kan zijn dat de api het niet doet. Bijvoorbeeld: "U probeert verbinding te maken naar data die niet bestaat", "Er kan geen verbinding worden gemaakt naar de API" of "Even geduld AUB, te veel requests". Ik kan die bepaalde responses wel in een if/elseif/else statement stoppen of in een switch. Maar een paar mensen raden mij aan om try en catch te gebruiken. Ik kan er alleen geen kaas van maken. Kan iemand mij in Jip en Janneke taal uitleggen wanneer je precies try en catch gebruikt en hoe dat precies met de front end communiceert?

Alvast bedankt!
 
PHP hulp

PHP hulp

22/12/2024 12:24:14
 
Thom nvt

Thom nvt

01/07/2021 11:17:15
Quote Anchor link
try-catch is voor het afvangen van Exceptions.
Die kunnen worden gegooid door de onderliggende code (API library, cURL, zelf geschreven, etc.) en geven aan dat er een uitzonderlijke situatie is opgetreden, oftewel iets wat niet verwacht word door de code.
Je kan de foutafhandeling dan in de catch omzetten naar een netter bericht voor je eindgebruiker of bijvoorbeeld een database-transactie terugdraaien, etc.

Een niet afgehandelde exception levert óf een error-pagina op (en dat hoort op productie systemen uit te staan) óf een 500 - Internal server error. Niet zo gebruiksvriendelijk dus.

Disclaimer: Onderstaande is gebaseerd op mijn ervaring/mening dus neem het niet aan als absolute waarheid of de beste oplossing.

In dit soort gevallen ben ik geen fan van if/else constructies, zeker als de lijst met fouten langer word.
switch/case is dan naar mijn mening netter, compacter en leesbaarder.

Voor wat betreft het terugmelden van fouten bestaan feitelijk 2 opties:
- Simpele melding dat iets mis is gegaan en de fout loggen.
- De fout beknopt en simpel doorgeven aan de gebruiker, zoals in jouw voorbeeld.

Het gevaar van de 2e strategie is dat je (te veel) je onderliggende structuur blootgeeft, wat een beveiligingsrisico kan zijn.
Ook interesseert het de gebruiker vaak niet wat mis gaat (en/of hij heeft onvoldoende kennis om te beoordelen wat nu te doen). De melding "Er is iets fout gegaan, probeer het later opnieuw" en de fout loggen is vaak al voldoende.
Wil je het écht netjes doen kun je nog automatisch een foutrapport mailen o.i.d.

Er is nog een 3e optie, het "inslikken" van de fout en niets doen. Waarom dat absoluut afgeraden word kun je misschien zelf wel bedenken ;)
Gewijzigd op 01/07/2021 11:18:38 door Thom nvt
 
Jorn Reed

Jorn Reed

01/07/2021 13:04:47
Quote Anchor link
Oh oke, bedankt voor je uitleg!

Ik dacht zelf namelijk echter dat een Exception (zelf geschreven error regeling) er voor zorgt dat er code fouten komen te staan, dus iets wat een eind gebruiker niet snapt. Daarom zat ik meer met if/else, of nog beter switch in mijn hoofd.
 
Thom nvt

Thom nvt

01/07/2021 13:36:35
Quote Anchor link
Als je met code fouten een stacktrace of fatal error bedoelt dan ja. Als je een exception gooit en die niet afvangt krijg je dat.
Als je een nette stacktrace wil kun je XDebug installeren, dat maakt het wat vriendelijker te lezen en makkelijker te backtracen.

Op productiesystemen hoor je dat uit te schakelen en geen XDebug te installeren, dat is een security risico en de gebruiker heeft er inderdaad niets aan.
Exceptions hoor je dan ook af te vangen, om te zetten in een nette error en te loggen zodat je kan uitzoeken wat er mis ging.
Of je dat met een if/else of switch/case doet is meer een kwestie van smaak dan wat anders.
 

01/07/2021 14:01:23
Quote Anchor link
Exceptions kunnen handig zijn om op een centrale plek fouten af te handelen. Stel je zit in een database transactie en je wilt op meerdere punten de transactie annuleren als er iets fout gaat,

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
<?php
// maak verbinding met database
try {
  // start transactie
  if (!$query1) {throw new Exception(eigen melding);}
  if (!$query2) {throw new Exception(nog een);}
  // sluit transactie af
} catch (Throwable $e) {
  // meld fout via $e->getMessage()
  // annuleer transactie

} finally {
  // verbreek database verbinding
}
?>


Voordelen:
- je mijdt een hoop if-statements

Nadelen:
- wat ik noem de 'scripting-ziekte', het is de bedoeling dat je je eigen objecttypen aanmaakt door de interface Throwable te extenden. Vervolgens kan je daarop differentiëren bij catch(), maar het is net als met Reflection minder snelle code dan wanneer je objecten voor alleen code gebruikt en variabelen alleen voor data.
- meerwaarde ten opzichte van gewone foutmelding is niet altijd evident:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
try {
  if ($ietsfout) {throw new Exception('foutje');}
}
catch (Throwable $e) {
  trigger_error($e->getMessage());
}


if ($ietsfout) {trigger_error('foutje');}  // kortere versie
?>

- voor beide situaties is er een algemene handler: set_exception_handler() en set_error_handler().

Meestal gebruik je PHP toch in CGI-setting met php-fpm, en dan is de code eigenlijk dusdanig rechtlijnig dat ik nog nooit echt behoefte heb gehad aan Exceptions.
Gewijzigd op 01/07/2021 14:01:55 door
 
Ward van der Put
Moderator

Ward van der Put

02/07/2021 09:19:26
Quote Anchor link
Een uitzondering is niet altijd een fout. Exceptions komen pas volledig tot hun recht wanneer je ze gaat gebruiken voor meer dan alleen errors.

Een voorbeeld:

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
<?php
declare(strict_types=1);

class InvoiceRepository
{
    /**
     * @param int $invoice_number Invoice number as an integer.
     * @return Invoice
     * @throws InvalidArgumentException Invalid invoice number.
     * @throws NotFoundException Invoice not found.
     */

    public function get(int $invoice_number): Invoice
    {
        // ...
    }
}

?>


De methode get() retourneert een Invoice-object voor een factuur, maar kan parallel aan de normale flow van de app met een InvalidArgumentException melden dat het factuurnummer onjuist is en met een NotFoundException dat de opgevraagde factuur niet kon worden gevonden. Met de $message of $code van een Exception kun je daarbij indien nodig ook nog doorgeven wat waarom precies fout gaat.

Zo krijg je code die expressiever is (wat gebeurt er precies) én die je een grotere controle geeft (over wat er precies gebeurt).
 

02/07/2021 10:37:52
Quote Anchor link
Goed voorbeeld, dank!
Alleen vrees ik dat ik niet slim genoeg ben om het voordeel te begrijpen.

Je hebt een functie die iets moet doen, dat is dan situatie A.
Als het niet gaat naar verwachting, krijg je situatie B of C, en dat gaat die code niet zelf oplossen, maar doorgeven.
Dat doorgeven kan op veel manieren, waarvan een Exception er maar 1 is.

Andere manieren zijn: de class Invoice uitbreiden met de status, of een aparte statusvariabele bij functie-aanroep als
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
public function get(int $invoice_number, string &$status) : Invoice
?>

Exceptions fungeren als een soort van doorgeefluik voor berichten, waarmee je meerdere berichten kan doorgeven. Als je dat zou willen oplossen met een eigen soort front controller patroon kan dat met de ingebouwde handler() functies van PHP.
Maar ook het debuggen van Exceptions wordt niet meteen simpeler, je moet van elk try{} -blok nagaan of alles wel goed afgehandeld wordt in het bijbehorende catch{} -blok (bij meerdere try{} -blokken).

De enige meerwaarde voor Exceptions die ik zie, is wanneer die berichten een bepaalde gelaagdheid hebben, dat ze op verschillende punten afgehandeld moeten worden in objectgeoriëenteerde code, waarbij je daarvoor zelf geen voorziening wilt of kunt bouwen.

Mijn indruk is dat PHP gewoon mee wil doen met andere programmeertalen, wat verder prima is. Maar voor mij biedt het weinig extra's, het is alsof PHP faciliteert in een veelgebruikt design pattern, ongeacht of het een meerwaarde heeft. Op diezelfde manier zou PHP ook een ingebouwde singleton class kunnen gaan leveren, die je zelf weer kunt extenden, wat een kwestie van smaak zou zijn.

Dus ik had liever een minimalistischer PHP, alleen moet ik niet zeuren want ik krijg vanalles gratis. Toch kijk ik alvast naar C, omdat je met PHP geen code kunt compileren tot programma's. Dit is vermeldenswaardig om aan te geven wat mijn bias is.
Gewijzigd op 02/07/2021 10:44:38 door
 
Ozzie PHP

Ozzie PHP

02/07/2021 11:42:33
Quote Anchor link
>> Alleen vrees ik dat ik niet slim genoeg ben om het voordeel te begrijpen.

Niet zo negatief over jezelf ;-)

Ik ben van huis uit geen programmeur en heb alles zelf (aan)geleerd. Door het lezen van boeken, door te oefenen, door te praten met andere programmeurs, door te doen en vooral door geïnteresseerd te zijn.

'Vroeger' dacht ik dat je dingen maar op 1 manier kon programmeren. Dat iets alleen zou werken als je het op een exact, specifieke manier bouwt. Dus stel: Ad, Ozzie en Ward zouden dezelfde opdracht krijgen (bouw een foto-gallerij) dan zouden wij na afloop exact 100% dezelfde code hebben geschreven, omdat dat de enige manier was waarop het geprogrammeerd kon worden. Dat is dus hoe ik er 'vroeger' over dacht. Inmiddels weet ik wel beter. Programmeren is als het schrijven van een boek. Begin- en eindpunt zijn duidelijk, maar op welke wijze je het verder invult is geheel afhankelijk van de schrijver. Dus stel we zouden alledrie een boek schrijven, dan zou het verhaal ongeveer op hetzelfde neerkomen, maar toch zou het door ieder van ons anders geschreven zijn.

Er zijn hier op het forum leden geweest die glashard beweerden dat iets op een bepaalde manier 'moet'. Je móet het precies op deze exacte manier programmeren, anders 'klopt' het niet. En dat 'kloppen' hield dan vaak in dat er (volgens de interpretatie van het forumlid) niet exact gehouden werd aan de (volgens de interpretatie van het forumlid) regels van het betreffende programmeerprincipe.

Ik kan me goed vinden in wat Ad Fundum zegt over het minimalisme. Omdat bepaalde dingen 'kunnen', hoef je ze nog niet per definitie te gebruiken. Ik schrijf zelf liever wat strakkere, compacte, snelle code die lekker overzichtelijk is en makkelijk te onderhouden. Anderen houden er juist weer van om meer 'wollige' code te gebruiken en tot in de details dicht te timmeren. Iedere mogelijke fout/uitzondering wordt op iedere plek waar mogelijk afgevangen en de code wordt een stuk langer.

Even Ward z'n voorbeeld:

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
<?php
declare(strict_types=1);

class InvoiceRepository
{
    /**
     * @param int $invoice_number Invoice number as an integer.
     * @return Invoice
     * @throws InvalidArgumentException Invalid invoice number.
     * @throws NotFoundException Invoice not found.
     */

    public function get(int $invoice_number): Invoice
    {
        // ...
    }
}

?>


Ward gooit in deze functie dus 2 exceptions. Dat is geen enkel probleem, maar je kan je afvragen waarom je het doet (ik zeg niet dat het goed of fout is).

In het commentaar lees ik bij InvalidArgumentException: Invalid invoice number.

Dit roept bij mij al een vraag op. Een ongeldig argument kan zijn dat een gebruiker als factuurnummer 'abc' invult, terwijl er alleen cijfers (bijv. 123) zijn toegestaan. Het argument(type) is dus ongeldig. Echter, de omschrijving heeft het over een ongeldig nummer. Wat is een ongeldig nummer? Is 'abc' een ongeldig nummer omdat het niet uit cijfers bestaat, of is 598945343 een ongeldig nummer omdat er maar 100 facturen in het systeem zitten. Of leveren beide gevallen een ongeldig argument op?

Dan de volgende: NotFoundException met als commentaar 'Invoice not found'.

Invoice not found. Hoe kan een factuur niet worden gevonden? Dat kan, lijkt mij, alleen als er een fout factuurnummer wordt opgevraagd (maar daar hadden we al een exception voor), of als iemand handmatig de betreffende factuur (het bestand) van de server heeft verwijderd. Echter heb je in zo'n geval te maken met een onbekwame programmeur, en dat lijkt me niet iets waarvoor je een exception zou moeten hanteren.

Kortom, we hebben 2 exceptions waarvan de toepassing voor mij persoonlijk niet geheel duidelijk is. Daarmee wil ik overigens niet zeggen dat het nut er niet is (Ward kennende heeft hij er namelijk heel goed over nagedacht).

Maar persoonlijk zou ik zo denken:

Iemand (een persoon) of iets (een proces) vraagt een factuur op. In het geval een proces dat doet, dan neem ik aan dat dat proces eerst controleert of het factuurnummer bestaat (haal alle factuurnummers van bedrijf X op). Hier kan eigenlijk niks fout gaan (mits goed geprogrammeerd). Een automatisch proces kan niet ineens letters gaan opvragen in plaats van cijfers. Op het moment dat een persoon een factuurnummer opvraagt, kan het wel fout gaan. Die kan inderdaad 'abc' opvragen in plaats van 123. Echter, dat lijkt mij niet zozeer een fout of uitzondering die zich voordoet in de Invoice class. En daarnaast ... als het goed is, heb je de input reeds gevalideerd voordat je het factuurnummer opvraagt, dus voordat je in die get functie komt, moet er al een controle hebben plaatsgevonden dat $invoice_number een getal is bestaande uit enkel cijfers. Dus de term 'invalid argument' is op dat moment al discutabel (afhankelijk van interpretatie). Het enige wat op dat moment nog 'fout' kan gaan is dat er een nummer wordt opgevraagd dat niet bestaat (nummer 9999 terwijl er maar 100 facturen zijn). Dat zou dan resulteren in een ... NotFoundException???

De vraag is dan ook ... als een gebruiker 9999 invoert in plaats van 99, moet daar dan een exception voor komen die logt dat iemand factuur 9999 heeft opgevraagd die niet bestaat? Ik zou denken van niet, omdat het nutteloze informatie is. Harstikke leuk dat iemand een verkeerd nummer invoert, maar waarom zou je dat loggen? Toon gewoon een foutmelding dat het nummer niet bestaat, zodat men het nogmaals kan proberen.

En goed ... zo kunnen we dus heel lang discussiëren. Wat ik bedoel te zeggen is dat wat voor de een prettig en logisch werkt, voor de ander niet per definitie het geval is. Ik denk dat het vooral belangrijk is dat je code schrijft die je zelf goed snapt en waarbij je je prettig voelt.
Gewijzigd op 02/07/2021 11:44:35 door Ozzie PHP
 
Thom nvt

Thom nvt

02/07/2021 11:58:57
Quote Anchor link
Ozzie PHP op 02/07/2021 11:42:33:
En daarnaast ... als het goed is, heb je de input reeds gevalideerd voordat je het factuurnummer opvraagt


Dat ligt er maar net aan, bijvoorbeeld:
Ik schrijf een library die facturen kan opvragen uit een ERP systeem. Die library geef ik vrij via packagist zodat anderen deze kunnen hergebruiken. Wie zegt dat die andere developer zijn validatie op orde heeft?
Als ik dan de API van die library documenteer is het (m.i.) veel gebruiksvriendelijker als ik beschrijf dat die method een Exception gooit als er iets fout is (of meerdere, maar het nut daarvan valt inderdaad te betwisten).

Dat is ook waar ik vaak Exceptions toepas, bibliotheken die ik elders wil hergebruiken. Dan hoef ik alleen de API te kennen en niet wat er binnenin precies gebeurt.

Ozzie PHP op 02/07/2021 11:42:33:
En goed ... zo kunnen we dus heel lang discussiëren. Wat ik bedoel te zeggen is dat wat voor de een prettig en logisch werkt, voor de ander niet per definitie het geval is. Ik denk dat het vooral belangrijk is dat je code schrijft die je zelf goed snapt en waarbij je je prettig voelt.



Dat is een waarheid als een koe. "Goede" code is een subjectief begrip en een grijs gebied, minder "goede" code is niet persé fout. Foute code is daarentegen vaak behoorlijk duidelijk fout.
 
Ozzie PHP

Ozzie PHP

02/07/2021 12:21:45
Quote Anchor link
@Thom nvt

En zo heeft iedereen dus zijn/haar eigen stijl.

Wat ik bedoel met die validatie, is dat ik die buiten de 'get' functie in de invoice class zou houden. Een functie zou in principe maar 1 verantwoordelijkheid moeten kennen, in dit geval het ophalen van een factuur aan de hand van een nummer. Op het moment dat je die get functie aanroept zou m.i. het meegegeven argument al gevalideerd behoren te zijn. Die validatie zou ik ergens anders (buiten de invoice class) onderbrengen, en op die plek kun je je eventuele foutafhandeling doen.

In jouw geval (als library) snap ik ook wel weer dat het gebruiksvriendelijker is om een dergelijke aanpak te gebruiken zoals jij dat doet. Zoals gezegd hangt veel af van de omstandigheden. heb je zelf wel of niet volledige controle? Zolang je in ieder geval maar begrijpt waarom je iets doet, en niet zomaar iets doet omdat iemand anders dat ooit toevallig ergens heeft gezegd ;)
Gewijzigd op 02/07/2021 12:23:49 door Ozzie PHP
 
Thom nvt

Thom nvt

02/07/2021 12:46:50
Quote Anchor link
Ozzie PHP op 02/07/2021 12:21:45:
Zolang je in ieder geval maar begrijpt waarom je iets doet, en niet zomaar iets doet omdat iemand anders dat ooit toevallig ergens heeft gezegd ;)

Hier kan ik het alleen maar roerend mee eens zijn.
 

02/07/2021 13:07:25
Quote Anchor link
Zoals een bekende Nederlander eerder al constateerde:
Quote:
Over smaak valt niet te twisten, maar over gebrèk aan smaak...

Dat brengt mij op een andere bekende Nederlander, met een onderbouwde mening over het schrijven van code.
Dit interview zou iedereen gezien moeten hebben.
https://www.vpro.nl/speel~WO_VPRO_035355~denken-als-discipline-noorderlicht~.html

Quote:
Kwaliteit, correctheid en elegantie is waar code aan moet voldoen.

Daaruit voorvloeiend:

Quote:
De competente programmeur is zich volledig bewust van de beperktheid van zijn eigen hersenpan.
Daarom benadert hij zijn programmeertaak met nederigheid.
Onder andere vermijdt hij slimmigheden als de pest.
Gewijzigd op 02/07/2021 13:10:09 door
 
Ozzie PHP

Ozzie PHP

02/07/2021 16:03:57
Quote Anchor link
Ad Fundum op 02/07/2021 13:07:25:

Wat een pionier :-)


Toevoeging op 02/07/2021 16:41:59:

Geen idee of iemand hier vroeger wel eens naar een computerclub is geweest? Ik wel ... dat was er eentje speciaal voor met name Commodore computers. Daar ging ik dan spelletjes scoren. Hier 2 rete-oude filmpjes van zo'n club ... dit was zo snel het enige dat ik op YouTube kon vinden. Wel erg grappig. Het is uit 1991, dus schrik niet van de fancy kapsels en verbluffende kwaliteit :-)



 

02/07/2021 20:41:23
Quote Anchor link
Ozzie PHP op 02/07/2021 16:03:57:
Wat een pionier :-)


Ja, en zijn standpunt "elegantie is een voorwaarde voor succes" is nog steeds actueel, de vraag hoe je programma's zo simpel en doeltreffend mogelijk maakt zou mijns inziens nog steeds voorop moeten staan. Dergelijke programma's zijn ook de meest efficiënte. Betere performance is zelfs beter voor het milieu, want kost minder stroom.

Wat Exceptions al kunnen throw-en zeg! :-)
 
Ozzie PHP

Ozzie PHP

02/07/2021 21:10:28
Quote Anchor link
Ad Fundum op 02/07/2021 20:41:23:
Wat Exceptions al kunnen throw-en zeg! :-)

Ja, bij hoge uitzondering ... ;-)
 
Ward van der Put
Moderator

Ward van der Put

03/07/2021 18:54:44
Quote Anchor link
Ozzie PHP op 02/07/2021 11:42:33:
In het commentaar lees ik bij InvalidArgumentException: Invalid invoice number.

Dit roept bij mij al een vraag op. Een ongeldig argument kan zijn dat een gebruiker als factuurnummer 'abc' invult, terwijl er alleen cijfers (bijv. 123) zijn toegestaan. Het argument(type) is dus ongeldig. Echter, de omschrijving heeft het over een ongeldig nummer. Wat is een ongeldig nummer? Is 'abc' een ongeldig nummer omdat het niet uit cijfers bestaat, of is 598945343 een ongeldig nummer omdat er maar 100 facturen in het systeem zitten. Of leveren beide gevallen een ongeldig argument op?


Je stelt vragen die de code gewoon beantwoordt. :O

Kennelijk was het voorbeeld inderdaad te moeilijk...
 
Ozzie PHP

Ozzie PHP

03/07/2021 22:02:25
Quote Anchor link
>> Je stelt vragen die de code gewoon beantwoordt. :O

Klopt, in dit geval beperkte ik me even tot de naamgeving van de exception en het bijbehorende commentaar.

Natuurlijk, je dwingt als parameter een integer af ... maar wat is dan de bedoeling van InvalidArgumentException? Wanneer is het argument invalid? Is een niet bestaand (factuur)nummer een ongeldig argument? Lijkt me niet. Volgens mij is dat gewoon geldig, maar bestaat de factuur niet ... maar dat zou een NotFoundException opleveren. Snap je wat ik bedoel?
 
Rob Doemaarwat

Rob Doemaarwat

04/07/2021 00:17:03
Quote Anchor link
Hoe je het precies inkleed boeit me niet zo, maar:

Als je *geen* exceptions gebruikt moet je bij elke functie een "speciale waarde" teruggeven als "er iets aan de hand was" (ongeldige parameter, whatever). Dan krijg je dat gedoe wat je wel vaker in PHP hebt: 0 is een valide response, maar als het fout is gegaan is het false ... lekker handig. Vervolgens moet je dit controleren, en moet de aanroepende functie ook weer een foutcode retourneren, enz. Als je een beetje gelaagd aan het programmeren bent (functie die functie aanroept, die functie aanroept, enz), moet je dus al die lagen diep zo'n "if fout, then return false, else ga verder" gedoe inbouwen.

Voordeel van exceptions is dat je een exception gooit, en dat de code meteen terugspringt naar het punt waar je 'm wilt vangen. Dus meteen alle lagen omhoog schiet, zonder dat je er hocus-pocus code voor hoeft te schrijven die het alleen maar onleesbaarder maakt (tenminste, zo zie ik het).

Je code gaat er dus steeds vanuit dat alles in orde is, en is dus to the point en duidelijk leesbaar. Als er iets niet in orde is (kan zijn) moet je op een gegeven moment (ergens bovenin de aanroep) een try..catch inbouwen die de exception vangt en een nuttige foutmelding geeft / iets in het log plaatst.

Persoonlijk vind ik dit veel makkelijker programmeren (leesbaarder, minder gedoe). Met dat hele if speciale response loop je altijd het risico dat je het een keer vergeet, en wordt zo'n false opeens gezien als een geldige waarden (en heb je bijvoorbeeld opeens iets verkocht voor 0 euro; of -1 euro, als dat je "magische waarde" is).
 

04/07/2021 08:12:38
Quote Anchor link
Ok, dus dit is een manier om fouten of iets wat je zelf hebt ge-throw-ed, op een gecentraliseerde plek af te vangen.

Een voordeel dat ik zou verwachten, is dat overkoepelende code meer zicht heeft op de context voor de functies die het aanroept, en dat als er iets niet werkt, iets anders kan worden gedaan om verder te gaan met het uitvoeren van de code waar de Exception in voorkwam. Iets als een continue keyword in een catch -blok.
Maar die functionaliteit bestaat niet in PHP.

Ik ben nog steeds zoekende naar de meerwaarde van Exceptions, want PHP heeft ook nog ziets als trigger_error() en set_error_handler(). Dat doet dan precies hetzelfde. En het is ook niet ongebruikelijk om in speciale gevallen een statusvariabele 'by reference' mee te geven aan een functie als je daar iets afwijkends mee wilt.

Omdat er technisch geen verschil is, ben ik verder gaan kijken dan m'n neus lang is, en anderen merken op de je met Exceptions de afhandeling van fouten buiten de uit te voeren code verplaatst. Dat komt de leesbaarheid van code ten goede naarmate er meer foutsituaties worden afgehandeld. Ook wanneer er verschillende programmeurs werken aan de code, heb je eenzelfde manier van werken wat de leesbaarheid ook bevordert.
Dus mijn eerste gedachte, dat PHP het ook moest hebben omdat Java het ook heeft, klopt niet helemaal.

En omdat je Exceptions ook kunt gebruiken als doorgeefluik voor berichten, kan je het ook misbruiken voor gekke dingen als bijvoorbeeld routing, wat ik nou niet echt leesbaarder vind.

Al met al is het gebruik van Exceptions vooral een kwestie van smaak, en het kan de leesbaarheid van de code bevorderen door het aantal if-statements te verminderen bij bijvoorbeeld transacties, of door (fout)afhandeling buiten de code te plaatsen (wat Rob al zei).
 
Ward van der Put
Moderator

Ward van der Put

04/07/2021 14:20:08
Quote Anchor link
Het een sluit het ander niet uit: errors zijn predefined exceptions.

Als je voldoende hebt aan errors alleen, kun je het bij errors laten. Heb je echter meer nodig, dan kun je errors ook als exceptions gebruiken. Zo kun je zelfs een systeem dat werkt met errors integreren in een ander systeem dat de voorkeur geeft aan exceptions.

Ozzie is bang dat er in ZIJN implementatie van mijn methode get(int $invoice_number) mét strict typing toch nog een string 'abc' door kan glippen. Kan gebeuren, maar dat zou je dan bijvoorbeeld zo kunnen afvangen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
try {
    $repo = new InvoiceRepository();
    $invoice = $repo->get($input);
}
catch (TypeError $e) {
    // Ik moet iets aan mijn $input doen.
}
?>


De error als exception. Dit is waarschijnlijk niet de meest elegante separation of concerns, maar wel een zorg minder: de app hoeft niet meer vast te lopen op een string 'abc' die wordt afgehandeld als een int $invoice_number.

Gaan vliegen zonder voldoende brandstof is dom, maar je zou tijdens een vlucht wel eens zonder voldoende brandstof kunnen komen te zitten. Het eerste is een regelrechte fout (error), het tweede meer een zeldzame uitzondering (exception).

De Standard PHP Library (SPL) maakt een soortgelijk onderscheid tussen logic exceptions en runtime exceptions. De LogicException is een programmeerfout die je in productie niet meer tegen zou moeten komen: een harde error. De RuntimeException is een fout die je vooral in productie kunt verwachten: een zachtere uitzondering.

Met een LogicException ga je liever niet vliegen. Bij een RuntimeException ben je aan het vliegen en zorg je dat je zo lang mogelijk in de lucht blijft. In de praktijk zul je beide in productie tegenkomen, maar de LogicException is een bug die er nog uit moet en de RuntimeException een voldongen feit die je code elegant moet kunnen afhandelen.

Exceptions zijn inderdaad een kwestie van stijl, maar naarmate je ze langer en vaker gebruikt, smaken ze vaak naar meer. Uitzonderingen daargelaten. ;-)
 
Ozzie PHP

Ozzie PHP

04/07/2021 16:26:03
Quote Anchor link
>> Uitzonderingen daargelaten. ;-)

Ja, het zijn altijd weer de uitzonderingen ;-)

>> Ozzie is bang dat er in ZIJN implementatie van mijn methode get(int $invoice_number) mét strict typing toch nog een string 'abc' door kan glippen.

Dat was niet helemaal wat ik zei. Mijn vraag lag meer in de logica ... middels strict typing dwing je een integer af. Daarnaast heb je in jouw voorbeeld dan nog een 'ongeldig nummer'-uitzondering en een 'factuur niet gevonden'-uitzondering.

Mijn vraag is enerzijds wat heb je er in de praktijk aan om te loggen dat iemand een fout nummer heeft opgevraagd (of log je dit niet maar gaat het enkel om het tonen van een foutmelding aan de gebruiker?) en anderzijds wanneer treedt de 'factuur niet gevonden'-uitzondering op. Als het nummer niet klopt, wordt automatisch de factuur ook niet gevonden. Óf gooi je die exception uitsluitend op het moment dat het nummer wél klopt, maar het bestand niet aanwezig is?

Dit laatste kan natuurlijk, maar dan is dus de vraag: hoe kan een bestand ineens niet meer aanwezig zijn. Dat moet dan gebeurd zijn door een handmatige actie/vergissing van een programmeur. Maar moet je daar dan speciaal een exception voor inbouwen? Kortom ... hoe ver moet je gaan?
 



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.