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.

Principe

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()
}

Lancer une exception

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"

Exemple : lancer une exception

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.

Capturer une exception

Pour capturer une exception on utilise une structure de contrôle try, catch (et éventuellement finally).

capturer une exception

A noter la syntaxe particulière du bloc catchcatch 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.

Exemple : capturer une exception

Etendre la classe Exception de PHP

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"

Exemple : étendre la classe Exception

Le code de la classe MonException sera placé dans le fichier monexception.class.php et inclus avec require dans le script principal.

Exercice : exceptions

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, ' &euro; - ', $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

Une solution possible

Exercice : exceptions