Les exceptions sont une autre façon de traiter le déclenchement des erreurs et leur traitement.
Pour signaler qu'une erreur s'est produite, une méthode lance une exception (ou lève une exception). Le code appelant la méthode doit capturer l'exception et traiter le problème s'il en est capable.
Quand une exception est lancée (mot-clé throw), l'interpréteur PHP arrête
l'exécution normale du script et transmet l'exception de bloc de code appelant en bloc de code
appelant.
Si PHP trouve un bloc capturant l'exception (mot-clé catch), l'exception est
traitée dans le code de ce bloc puis le script continue son exécution juste après le bloc
catch.
Si aucun bloc catch n'est rencontré, l'interpréteur PHP affiche le message d'erreur de l'exception et arrête le script.
Une exception est une instance de la classe Exception. Cette classe est native dans
PHP et se compose des membres suivants :
class Exception {
/* Propriétés */
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
/* Méthodes */
public __construct([$msg = "" [,$num = 0 [, $prev = NULL ]]])
final public string getMessage()
final public Exception getPrevious()
final public mixed getCode()
final public string getFile()
final public int getLine()
final public array getTrace()
final public string getTraceAsString()
public string __toString()
final private void __clone()
}
Pour lancer une exception on utilise le mot-clé throw suivi de l'instanciation
d'une nouvelle Exception.
thow new Exception("Le message d'erreur à afficher");
PHP ne permet pas de lancer d'exception dans un destructeur. Si c'est le cas, le script s'arrête avec une erreur fatale "Exception thrown without a stack frame in Unknown on line 0"
Comme vous le voyez en testant le code, nous avons une erreur qui nous dit que nous avons lancé une exception sans la capturer. Voyons donc comment traiter cette exception.
Pour capturer une exception on utilise une structure de contrôle try, catch
(et éventuellement finally).
A noter la syntaxe particulière du bloc catch où catch est
pratiquement considéré comme une fonction à laquelle on passe en paramètre une référence sur
l'instance de l'Exception à traiter.
A l'intérieur de ce bloc, on va pouvoir invoquer diverses méthodes de la classe Exception
si on veut réaliser des affichages sur les causes de l'erreur.
L'exemple suivant utilise les méthodes getMessage(), getLine(), getFile(), getTrace() et __toString() de la classe prédéfinie Exception.
PHP permet d'étendre la classe Exception prédéfinie dans le langage. Nous pouvons
ainsi écrire nos propres exceptions, adaptées à nos développements particuliers, et ne gérer que
ces exceptions "prévisibles" (comme par exemple les mauvaises valeurs passées en paramètres).
Toutes les méthodes de la classe Exception ne sont pas redéfinissable ou
surchargeables. Seules les méthodes non finales peuvent être réécrites, soit __construct()
et __toString().
Dans l'exemple suivant, notre classe MonException surchage le constructeur
de la classe Exception pour accepter 2 paramètres :
- le 1er paramètre peut être soit un numéro, soit un texte. Le numéro donnera accès à un message
d'erreur (attribut de notre classe MonException). Procéder ainsi permet de stocker
les messages d'erreur dans un endroit bien repéré et facilite par exemple les traductions des
textes. En acceptant malgré tout un texte comme paramètre, on laisse une ouverture aux
utilisateurs de notre classe.
- le 2éme paramètre est un booléen qui indique si l'exception est bloquante ou non. Par défaut
il a la valeur true et arrête le script après affichage du message d'erreur.
La méthode __toString()
est redéfinie pour afficher les messages d'erreur de 2 façons :
- si nous sommes en phase de développement et de debuggage, l'affichage sera détaillé.
- si nous sommes en phase de production, l'affichage sera très réduit.
Il ne faut jamais lancer d'exception dans la classe qui étend Exception car on
provoquerait alors une boucle infinie. Si c'est le cas, le script s'arrête avec une erreur
fatale "Exception thrown without a stack frame in Unknown on line 0"
Le code de la classe MonException
sera placé dans le fichier monexception.class.php et inclus avec require dans le
script principal.
Reprenez le code de la classe Livre ci-dessous avec le mécanisme des
exceptions pour gérer les erreurs. Utilisez la classe du fichier monexception.class.php ou écrivez votre
propre classe.
// Définition de la classe Livre
class Livre {
const CAT_METHODE = 'Méthode';
const CAT_PARTITION = 'Partition';
const CAT_BIO = 'Biographie';
const CAT_AUTRE = 'Autre';
private $titre, $auteur, $pages, $prix, $cat;
public function __construct($p1, $p2, $p3, $p4, $p5) {
$this->titre = $this->verifChaine($p1, 'titre');
$this->auteur = $this->verifChaine($p2, 'auteur');
if (is_numeric($p3) && estEntre($p3, 10, 1000)) {
$this->pages = $p3;
} else {
$this->afficheErreur($p3, 'pages');
}
if (is_numeric($p4) && estEntre($val, 0, 1000)) {
$this->prix = $p4;
} else {
$this->afficheErreur($p4, 'prix');
}
$oks = array(self::CAT_METHODE, self::CAT_PARTITION,
self::CAT_BIO, self::CAT_AUTRE);
if (in_array($p5, $oks)) {
$this->cat = $p5;
} else {
$this->afficheErreur($p5, 'cat');
}
}
private function verifChaine($val, $attr) {
$val = trim($val);
($val == '') && $this->afficheErreur($val, $attr);
return $val;
}
private function afficheErreur($val, $attr) {
exit("<hr>Valeur '<b>$val</b>' invalide pour
l'attribut <b>$attr</b>.<hr>");
}
public function decrire() {
echo '<h4>Instance de la classe Livre</h4>',
$this->titre, ' - ', $this->auteur, ' - ',
$this->pages, ' pages - ',
$this->prix, ' € - ', $this->cat, '<hr>';
}
} // Fin de la classe Livre
Vous devez tester votre code en instanciant des Livre avec les informations
suivantes qui provoqueront toutes des erreurs :
| Titre | Auteur | Nb Pages | Prix | Cat. |
| Pas de titre | 70 | 17 | Méthode | |
| Pas d'auteur | 160 | 4.90 | Méthode | |
| Mauvais nombre de pages | Mauvais prix | 0 | -21.90 | Partition |
| Seulement le titre OK | inconnu | 30 euros | Magazine |