Uitbreiden van de standaard Exception klasse

Er zijn situaties waarbij de functionaliteit van de standaard Exception klasse niet voldoende is. In deze gevallen is het het makkelijkst om de standaard klasse eenvoudigweg uit te breiden. Dit kunnen we doen door een eigen exeception klasse te schrijven die de standaard klasse 'extend'.

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
45
46
47
48
49
50
51
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);

class MyException extends Exception
{
    public function getError()
    {

        $sMessage = 'Er is een fout opgetreden in '.$this->getFile().' op regel '.$this->getLine().'<br />';
        $sMessage .= 'Foutmelding: <i>'.$this->getMessage().'</i><br />';
        
        return $sMessage;
    }
}

class Gebruiker
{
    protected $sGebruikersnaam;
    protected $iLeeftijd;
    protected $sAvatar;
    protected $sDir = 'avatars/';
    
    function
__construct($sGebruikersnaam, $iLeeftijd, $sAvatar)
    {

        if(strlen($sGebruikersnaam) < 3)
        {

            throw new MyException('Aanmaken instantie van "'.__CLASS__.'" mislukt: Gebruikersnaam moet minimaal 3 tekens zijn.');
        }

        if(!is_numeric($iLeeftijd))
        {

            throw new MyException('Aanmaken instantie van "'.__CLASS__.'" mislukt: Geen geldige leeftijd ingevuld');
        }

        if(!file_exists($this->sDir.$sAvatar))
        {

            throw new MyException('Aanmaken instantie van "'.__CLASS__.'" mislukt: Gekozen avatar bestaat niet');
        }

        
        $this->sGebruikersnaam = $sGebruikersnaam;
        $this->iLeeftijd = $iLeeftijd;
        $this->sAvatar = $sAvatar;
    }
}


try
{
    $gebruiker = new Gebruiker('Henk', 25, 'plaatje.png');
}

catch(MyException $e)
{

    echo $e->getError();
}

?>

De klasse MyException is een voorbeeld van een zelf geschreven exception klasse. Aangezien dit een uitbreiding is van de standaard klasse, hebben we de beschikking over alle members en methoden uit die standaard klasse.

In dit voorbeeld gebruiken we de methode getError() om een zelf geschreven error weer te geven waarin verschillende methoden uit de standaard klasse verwerkt zijn. Ook zien we dat we nu geen 'new Exception' gooien, maar een 'new MyException'. Ook bij het afvangen van de exception gebruiken we MyException.

De output van dit voorbeeld is:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
Er is een fout opgetreden in C:\wamp\www\test.php op regel 34
Foutmelding: Aanmaken instantie van "Gebruiker" mislukt: Gekozen avatar bestaat niet

Nu is het ook mogelijk om meerdere zelf geschreven exception klasses te gebruiken voor verschillende fouten. Deze klasses kunnen een uitbreiding van de Exception klasse zijn of van elkaar.
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);

class MyException extends Exception
{
    public function getError()
    {

        $sMessage = 'Er is een fout opgetreden in '.$this->getFile().' op regel '.$this->getLine().'<br />';
        $sMessage .= 'Foutmelding: <i>'.$this->getMessage().'</i><br />';
        
        return $sMessage;
    }
}

class AvatarException extends Exception
{
    public function avatarError()
    {

        $sMessage = 'Er is een fout opgetreden bij het laden van de avatar: "'.$this->getMessage().'"<br />';
        return $sMessage;
    }
}

class Gebruiker
{
    protected $sGebruikersnaam;
    protected $iLeeftijd;
    protected $sAvatar;
    protected $sDir = 'avatars/';
    
    function
__construct($sGebruikersnaam, $iLeeftijd, $sAvatar)
    {

        if(strlen($sGebruikersnaam) < 3)
        {

            throw new MyException('Aanmaken instantie van "'.__CLASS__.'" mislukt: Gebruikersnaam moet minimaal 3 tekens zijn.');
        }

        if(!is_numeric($iLeeftijd))
        {

            throw new MyException('Aanmaken instantie van "'.__CLASS__.'" mislukt: Geen geldige leeftijd ingevuld');
        }

        if(!file_exists($this->sDir.$sAvatar))
        {

            throw new AvatarException('Gekozen avatar bestaat niet');
        }

        
        $this->sGebruikersnaam = $sGebruikersnaam;
        $this->iLeeftijd = $iLeeftijd;
        $this->sAvatar = $sAvatar;
    }
}


try
{
    $gebruiker = new Gebruiker('Henk', 25, 'plaatje.png');
}

catch(MyException $e)
{

    echo $e->getError();
}

catch(AvatarException $e)
{

    echo $e->avatarError();
    echo 'Bestand: '.$e->getFile().'<br />';
    echo 'Regel: '.$e->getLine().'<br />';
    echo 'Uitvoer van het script wordt gestopt...';
    exit();
}

?>

Wederom gaat het in bovenstaande code fout omdat de gekozen avatar niet bestaat. Nu wordt er echter een AvatarException gegooid als dat gebeurt. In alle andere gevallen wordt een MyException gebruikt.

Omdat er nu twee mogelijke exceptions zich voor kunnen doen, moeten we ook zorgen dat we beide soorten afvangen. We hebben nu dus twee catck blokken nodig om dit af te handelen. In bovenstaand voorbeeld wordt natuurlijk het catch blok, waarin de AvatarException afgevangen wordt, uitgevoerd.

De output is dan ook als volgt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
Er is een fout opgetreden bij het laden van de avatar: "Gekozen avatar bestaat niet"
Bestand: C:\wamp\www\test.php
Regel: 42
Uitvoer van het script wordt gestopt...

We zien dat we, ondanks dat we een zelf geschreven klasse gebruiken, nog steeds de beschikking hebben over de methoden getFile() en getLine() uit de standaard klasse. Dat is de mooie eigenschap van het extenden van klasses.

Voorbeeld van PDO foutafhandeling
Eerder in deze tutorial heb ik de foutafhanding bij een sql query behandeld. Daar gebruikten we trigger_error() om een fout van MySQL op te halen en weer te geven.

Tegenwoordig wordt steeds vaker gebruik gemaakt van PDO om de connectie met een database te beheren. Een voorbeeld van hoe je de foutafhandeling bij PDO zou kunnen toepassen:
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
<?php
try
{
    $db = new PDO('mysql:host=localhost;dbname=test','user','password');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $sql = "SELECT naam FROM bestaat_niet";
    $results = $db->query($sql);
    
    foreach($results as $row)
    {

        echo $row['naam'].'<br>';
    }
}

catch(PDOException $e)
{

    echo '<pre>';
    echo 'Regelnummer: '.$e->getLine().'<br>';
    echo 'Bestand: '.$e->getFile().'<br>';
    echo 'Foutmelding: '.$e->getMessage().'<br>';
    echo '</pre>';
}

?>

We zien hier dat PDO ook gebruik maakt van een eigen exception klasse, namelijk PDOException. Deze klasse wordt gebruikt om fouten die zich voordoen tijdens het gebruik van de PDO klasse te verwerken.

Een voorbeeld van de output zou deze kunnen zijn:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
Regelnummer: 8
Bestand: /Users/jorendewit/Sites/jorendewit/phphulp/pdo.php
Foutmelding: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.bestaat_niet' doesn't exist

Meer over PDO kun je in deze tutorial vinden.

Foutafhandeling bij de Swift mailer klasse
Een ander voorbeeld waar gebruik gemaakt wordt van custom exception klasses, is bij het gebruik van Swift mailer.
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
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);

try
{
    $swift = new Swift(new Swift_Connection_SMTP('smtp.server.nl'));
    $message = new Swift_Message('Onderwerp', 'Body');
    
    $swift->send($message, '[email protected]', '[email protected]');
    echo 'Bericht verstuurd';
}

catch (Swift_ConnectionException $e)
{

    echo 'Er is een foutopgetreden bij het verbinden met de SMTP server: ' . $e->getMessage();
}

catch (Swift_Message_MimeException $e)
{

    echo 'Er is een fout opgetreden bij het opbouwen van het mailtje: ' . $e->getMessage();
}

?>

Duidelijk is ook hier weer het verschil tussen de twee exception klasses die gebruikt worden. Waar Swift_ConnectionException gebruikt wordt om een fout in de verbinding met de server af te handelen, zal er een Swift_Message_MimeException gegooid worden als het aanmaken van het mailtje niet lukt.

Zoals je ziet biedt het gebruik van exceptions je heel veel ruimte om je foutafhandeling zo toe te passen als jij dat zelf wilt. Hoe complex je de foutafhandeling maakt hangt natuurlijk af van het soort applicatie dat je maakt en van de methode waarop jij gebruikers in aanraking wilt laten komen met foutmeldingen.

« Lees de omschrijving en reacties

 
 

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.