exceptions... daar gaan we weer

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 3 volgende »

Ozzie PHP

Ozzie PHP

04/12/2013 20:10:14
Quote Anchor link
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:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?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?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?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?
 
PHP hulp

PHP hulp

03/12/2024 20:01:01
 
Reshad F

Reshad F

04/12/2013 20:22:30
Quote Anchor link
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?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php

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

Ozzie PHP

04/12/2013 20:32:49
Quote Anchor link
>> 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:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?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?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?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?
 
Wouter J

Wouter J

04/12/2013 22:40:01
Quote Anchor link
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.
 
Ozzie PHP

Ozzie PHP

04/12/2013 22:45:49
Quote Anchor link
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?
 
Wouter J

Wouter J

04/12/2013 22:46:18
Quote Anchor link
Jup
 
Ozzie PHP

Ozzie PHP

04/12/2013 23:00:59
Quote Anchor link
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!
Gewijzigd op 04/12/2013 23:06:54 door Ozzie PHP
 
- Raoul -

- Raoul -

04/12/2013 23:06:34
Quote Anchor link
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!
Gewijzigd op 04/12/2013 23:07:38 door - Raoul -
 
Wouter J

Wouter J

04/12/2013 23:26:49
Quote Anchor link
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.
 
Ozzie PHP

Ozzie PHP

04/12/2013 23:36:01
Quote Anchor link
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.
 
- Raoul -

- Raoul -

04/12/2013 23:39:52
Quote Anchor link
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!
 
Wouter J

Wouter J

04/12/2013 23:55:04
Quote Anchor link
Als je de cache data verwijderd kan je 2 dingen doen: je roept zelf de filesystem aan of de cacher verwijderd de bestanden die die gemaakt heeft. Het aanroepen van de delDir functie is niet de verantwoordelijkheid van de cacher
 
Ozzie PHP

Ozzie PHP

05/12/2013 00:00:11
Quote Anchor link
@Raoul:
>> maar je het is best dat je die NIET opvangt in je filecacher class

Oké, maar hoe weet class Foo dan dat de directory niet is verwijderd? Zoals jij het nu beschrijft, gooit de cacher class dus geen exception. Hoe zou class Foo dan moeten weten dat het verwijderen is mislukt?

@Wouter:
>> Het aanroepen van de delDir functie is niet de verantwoordelijkheid van de cacher

Waarom niet? Het gaat dus om een FILEcacher. Alle cachers ondersteunen de methode deleteAll(). Class Foo doet dus dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$this
->cacher->deleteAll();
?>

Class Foo weet niet dat het een filecacher is en hoeft dit ook niet te weten. Om de directory te verwijderen maakt de filecacher class gebruik van de filesystem class. Ik zie het probleem niet waarom dat niet zou kunnen?
 
Ward van der Put
Moderator

Ward van der Put

05/12/2013 08:33:17
Quote Anchor link
Je moet de vraag misschien omkeren: wil je iets kunnen doen waarvoor je een exception nodig hebt?

Voor een filecache lijkt mij dat namelijk overbodig. Als we eens een eenvoudige CacheInterface voor alle soorten caches lenen, hebben bijna alle methoden een return bool:

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
27
28
<?php
interface CacheInterface extends \ArrayAccess
{
    /**
     * @param string $key
     * @return EntryInterface
     */

    public function get($key);

    /**
     * @param string $key
     * @return bool
     */

    public function isset($key);

    /**
     * @param EntryInterface $entry
     * @return bool
     */

    public function set(EntryInterface $entry);

    /**
     * @param string $key
     * @return bool
     */

     public function unset($key);
}

?>


Voor een filecache kun je deze interface implementeren met filesystem-functies die ook bool retourneren:

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
<?php
class FileCache implements CacheInterface
{
    // CacheInterface::isset() implementeren met file_exists()
    public function isset($key)
    {

        if (is_string($key)) {
            return file_exists($key);
        }
else {
            return false;
        }
    }


    // CacheInterface::unset() implementeren met unlink()
    public function unset($key)
    {

        if ($this->isset($key)) {
            return unlink($key);
        }
else {
            return false;
        }
    }
}

?>


Waarom heb je hier exceptions nodig als je het eenvoudig afkunt met een true of false?
 
Ozzie PHP

Ozzie PHP

05/12/2013 12:16:21
Quote Anchor link
Hmmm, interessante benadering. Zit wel iets in in wat je zegt.

Maar... jij gebruikt nu dan dus unlink om een bestand te verwijderen. Stel nu dat dat niet lukt, omdat de maprechten van de bovenliggende directory dit niet toestaan, dan zou je toch een exception willen gooien? Dat is dan toch (zoals Wouter het zegt) een uitzondering?
 
Chris -

Chris -

05/12/2013 12:39:59
Quote Anchor link
Offtopic:
@Ward: In de comments van je voorbeeld benader je 'm als static, maar zo zijn ze niet gedefinieerd ;)


Overigens ben ik wel benieuwd naar de antwoorden van Wouter en Ward. Het is sowieso een negatief resultaat, maar in dit geval is het wel van dusdanige aard dat "je niet verder kan" :/ (behalve dan implementatie om het op meerdere manieren te verwijderen, maar als het resultaat dan alsnog negatief blijft lijkt het me een exception..)
 
Ward van der Put
Moderator

Ward van der Put

05/12/2013 13:43:20
Quote Anchor link
Het is een keuze. De CacheInterface schrijft return bool voor. Dan lijkt een return false me afdoende als er een FilesystemException optreedt in de FileCache.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
class FileCache implements CacheInterface
{
    /** @type Filesystem */
    private $fs;

    public function __construct()
    {

        $this->fs = new Filesystem();
    }


    /**
     * @param string $key
     * @return bool
     */

    public function isset($key)
    {

        if (!is_string($key)) {
            return false;
        }

        try {
            return $this->fs->exists($key);
        }
catch (FilesystemException $e) {
            return false;
        }
    }


    /**
     * @param string $key
     * @return bool
     */

    public function unset($key)
    {

        if (!$this->isset($key)) {
            return false;
        }

        try {
            return $this->fs->remove($key);
        }
catch (FilesystemException $e) {
            return false;
        }
    }
}

?>


Hier spelen verschillende overwegingen mee.

Of je niet verder kunt zonder filecache, is maar de vraag. Waarschijnlijk werkt je applicatie langzamer zonder cache. Daarvoor heb je die cache immers. Maar dat is geen dwingende reden om de boel plat te laten gaan zonder cache.

Misschien heb je wel verschillende caches. En kun je dus uitwijken naar een andere cache als er eentje het laat afweten. Kiest u maar:

• class MemCache implements CacheInterface
• class SessionCache implements CacheInterface
• class FileCache implements CacheInterface
• class DatabaseCache implements CacheInterface
• class CloudCache implements CacheInterface

Een derde reden is performance. Niet onbelangrijk voor een cache. Als je het gaat testen, blijkt er géén snelheidsverschil te zijn tussen een oplossing zonder en een oplossing met exceptions, zolang het aantal exceptions maar verwaarloosbaar klein is. PHP-code voor exception handling zit dus niet in de weg.

Naarmate er meer exceptions optreden, wordt de oplossing met exception handling echter significant langzamer. Het snelheidsverschil loopt op tot een factor 10 (1000% langzamer) als je 100% exceptions benadert. Vooral bij een kleine cache met veel cache misses wil je geen exceptions zien.

Ik denk kortom dat je applicatie een exception moet gooien op een return false van een benaderde cache — en alleen als de applicatie daarvan daadwerkelijk hinder ondervindt.
 
Ozzie PHP

Ozzie PHP

05/12/2013 14:08:54
Quote Anchor link
Dit heeft dus alles te maken met de vraag die ik eerder stelde. Waar is een exception voor bedoeld? Wat is de functie van een exception en waar gebruik je een exception voor? Wouter zegt hierboven dat een exception een uitzondering is.

Op het moment dat je cache data (uit de database of uit een bestand) wilt verwijderen en het lukt niet, of omdat de data niet bestaat, of omdat de data wegens technische redenen niet verwijderd kan worden... is er dan sprake van een uitzonderingssituatie? Ja, ik zou denken van wel. Ik wil iets verwijderen. Normaal lukt dat altijd, maar nu ineens niet! * ping * Uitzondering!

Ik denk dus dat de 1e vraag moet zijn: is er sprake van een uitzondering? En de 2e vraag moet zijn: wat kunnen we met die uitzondering doen? Die kunnen we in ieder geval loggen/mailen naar de webmaster, zodat deze kan kijken wat er aan de hand is.

De key question lijkt mij in ieder geval: als ik iets wil verwijderen en dat blijkt niet te kunnen (omdat het niet bestaat of technisch niet mogelijk is) is er dan sprake van een uitzondering? Wat vinden jullie?

Graag reacties!
 
Ward van der Put
Moderator

Ward van der Put

05/12/2013 14:56:25
Quote Anchor link
Ozzie PHP op 05/12/2013 14:08:54:
Op het moment dat je cache data (uit de database of uit een bestand) wilt verwijderen en het lukt niet, of omdat de data niet bestaat, of omdat de data wegens technische redenen niet verwijderd kan worden... is er dan sprake van een uitzonderingssituatie? Ja, ik zou denken van wel. Ik wil iets verwijderen. Normaal lukt dat altijd, maar nu ineens niet! * ping * Uitzondering!
Het is maar hoe je het ontwerpt. In jouw ontwerp kan dit een uitzonderlijke situatie zijn, in een ander ontwerp eerder regel dan uitzondering.

Je kunt bijvoorbeeld ook eenvoudig stellen: dat wat jij nu wilt verwijderen, is al verwijderd. Oh mooi, dan hoeven we dat niet nog een keer te proberen.

Dat is een ander ontwerp, maar je moet er vooral geen waardeoordeel aan verbinden en meteen "Error!" gaan schreeuwen.

Daarom kan het Filesystem hier een exception gooien (cachebestand bestaat niet) en FileCache daaraan zelf een conclusie verbinden (maakt mij niet uit). Voor een andere klasse of applicatie kan dezelfde exception geheel andere gevolgen hebben: "Chips, dat is niet pluis, laten we Ozzie een sms sturen."
Gewijzigd op 05/12/2013 14:57:15 door Ward van der Put
 
Ozzie PHP

Ozzie PHP

05/12/2013 15:21:43
Quote Anchor link
Dat is dus ook een beetje waar ik mee stoei. Om voor mezelf duidelijk te krijgen wanneer iets wel of niet een exception is/behoort te zijn.

Van de ene kant is het logisch dat een cachebestand soms niet bestaat, omdat het bijvoorbeeld verouderd is en het (handmatig of via de code) is verwijderd. Op het moment dat je dan dat cachebestand gaat laden, kan het goed zijn dat het niet bestaat. In de catch zou je dan alsnog de data laden en cachen. Maar ik zou dan toch nog denken dat het een uitzondering is. "Normaal bestaat de cache data, maar nu niet. Dus een uitzonderingssituatie." Weliswaar eentje die vaker kan voorkomen.

Ik las ook ergens in een tutorial over exceptions, dat ze dienen om te voorkomen dat een functie informatie returnt of de functie wel of niet sucesvol is uitgevoerd. Als je een bestand laadt, zo werd gesteld, dan behoort de functie alleen dat te doen, en geen "status"-data te retourneren (false, true, null) omdat dat niet het doel van de functie is. Om in te grijpen als het fout gaat, gebruik je exceptions zo werd het daar gezegd. Uiteraard mag een functie best een boolean retourneren, maar de functie moet daar dan wel voor geschreven zijn, denk aan functies als dataExists(), isLoggedIn() enz. Maar een load functie zou dus alleen iets mogen laden, en op het moment dat het mis gaat een exception gooien.
 
Ward van der Put
Moderator

Ward van der Put

05/12/2013 15:58:05
Quote Anchor link
Ozzie PHP op 05/12/2013 15:21:43:
Ik las ook ergens in een tutorial over exceptions, dat ze dienen om te voorkomen dat een functie informatie returnt of de functie wel of niet sucesvol is uitgevoerd.

Heb je een linkje naar die tutorial?
 

Pagina: 1 2 3 volgende »



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.