W3docs

Comprendre les exceptions PHP

En PHP, les exceptions permettent de gérer les erreurs inattendues et les problèmes d'exécution de façon structurée avec try, catch et finally.

Une exception est un objet qui représente une erreur ou une condition inattendue interrompant le déroulement normal de votre programme. Au lieu de retourner un code d'erreur que l'appelant pourrait oublier de vérifier, le code « lève » une exception ; l'exécution déroule alors la pile d'appels jusqu'à trouver un bloc catch correspondant. Si aucun bloc ne la capture, le script s'arrête avec une erreur fatale.

Ce chapitre explique comment lever et capturer des exceptions, les méthodes exposées par chaque exception (getMessage(), getCode(), getLine(), getFile()), le bloc finally, les blocs catch multiples, les classes d'exceptions personnalisées et la différence entre Exception et Error.

Qu'est-ce qu'une exception PHP ?

Une exception PHP est un objet qui descend de la classe intégrée Exception (ou, plus généralement, de l'interface Throwable). Quand quelque chose se passe mal — un fichier manquant, un argument invalide, une connexion à la base de données échouée — vous créez l'un de ces objets et le throw (lancez). Lancer une exception arrête immédiatement le chemin d'exécution en cours et passe le contrôle au gestionnaire englobant le plus proche.

Utilisez une exception lorsqu'une fonction ne peut pas continuer de façon significative et que c'est l'appelant qui doit décider quoi faire ensuite. N'en utilisez pas pour un flux de contrôle ordinaire (une recherche normale « utilisateur introuvable » s'exprime mieux avec une valeur de retour).

Lever une exception

Le mot-clé throw lève une exception, suivi d'une nouvelle instance d'une classe d'exception. Le constructeur accepte un message optionnel, un code entier et une exception précédente (pour le chaînage) :

<?php

function divide(int $a, int $b): float
{
    if ($b === 0) {
        throw new InvalidArgumentException('Division by zero is not allowed.');
    }
    return $a / $b;
}

try {
    echo divide(10, 0);
} catch (InvalidArgumentException $e) {
    echo 'Error: ' . $e->getMessage();
}
?>

Résultat :

Error: Division by zero is not allowed.

Le code à l'intérieur de try s'exécute normalement jusqu'à ce que throw se déclenche. À partir de ce moment, le reste du bloc try est ignoré et le bloc catch correspondant s'exécute.

Gérer les exceptions avec try / catch

Vous encadrez le code susceptible d'échouer dans un bloc try et récupérez l'échec dans un bloc catch. La variable dans catch (ici $e) contient l'objet exception, qui expose plusieurs méthodes en lecture seule :

MéthodeRetourne
getMessage()Le message lisible par l'humain
getCode()Le code entier passé au constructeur
getLine()La ligne où l'exception a été levée
getFile()Le fichier où elle a été levée
getPrevious()L'exception « précédente » chaînée, le cas échéant
getTraceAsString()La trace de pile sous forme de chaîne
<?php

try {
    throw new Exception('Something failed', 42);
} catch (Exception $e) {
    echo 'Message: ' . $e->getMessage() . PHP_EOL;
    echo 'Code: ' . $e->getCode() . PHP_EOL;
}
?>

Résultat :

Message: Something failed
Code: 42

Capturer plusieurs types d'exceptions

Un seul bloc try peut avoir plusieurs blocs catch. PHP les vérifie du haut vers le bas et exécute le premier dont le type correspond. Depuis PHP 7.1, vous pouvez également capturer plusieurs types non liés dans un seul bloc avec l'opérateur pipe (|) :

<?php

try {
    throw new RuntimeException('Network is down');
} catch (InvalidArgumentException $e) {
    echo 'Bad argument: ' . $e->getMessage();
} catch (RuntimeException | LogicException $e) {
    echo 'Runtime/logic problem: ' . $e->getMessage();
}
?>

Résultat :

Runtime/logic problem: Network is down

L'ordre est important : listez les types d'exceptions plus spécifiques avant leurs classes parentes, sinon le catch général engloutit tout en premier.

Le bloc finally

Le bloc finally est optionnel mais utile. Son code s'exécute toujours — qu'une exception ait été levée ou non, et même si le bloc try ou catch exécute un return. C'est donc l'endroit idéal pour le nettoyage, comme la fermeture d'un descripteur de fichier ou la libération d'un verrou :

<?php

try {
    echo 'Open resource' . PHP_EOL;
    throw new Exception('Boom');
} catch (Exception $e) {
    echo 'Caught: ' . $e->getMessage() . PHP_EOL;
} finally {
    echo 'Cleanup always runs' . PHP_EOL;
}
?>

Résultat :

Open resource
Caught: Boom
Cleanup always runs

Classes d'exceptions personnalisées

Au-delà des types intégrés, vous pouvez définir vos propres classes d'exceptions en étendant Exception. Une classe personnalisée vous permet de transporter des données supplémentaires (comme une valeur qui a échoué) et permet aux appelants de catcher votre type d'erreur spécifique sans capturer accidentellement des erreurs non liées :

<?php

class InsufficientFundsException extends Exception
{
    private float $shortfall;

    public function __construct(float $shortfall)
    {
        $this->shortfall = $shortfall;
        parent::__construct("Short by $shortfall");
    }

    public function getShortfall(): float
    {
        return $this->shortfall;
    }
}

try {
    throw new InsufficientFundsException(25.5);
} catch (InsufficientFundsException $e) {
    echo $e->getMessage() . PHP_EOL;
    echo 'Need ' . $e->getShortfall() . ' more.';
}
?>

Résultat :

Short by 25.5
Need 25.5 more.

PHP fournit également une famille d'exceptions SPL prêtes à l'emploi — InvalidArgumentException, RuntimeException, LengthException, et d'autres — vous n'avez donc souvent pas besoin d'en inventer de nouvelles.

Exception vs. Error

Depuis PHP 7, les échecs internes du moteur (comme une erreur de type ou l'appel d'une méthode indéfinie) sont lancés sous forme d'objets Error, non d'objets Exception. Les deux implémentent l'interface Throwable. Un simple catch (Exception $e) ne capturera pas une Error. Pour gérer les deux, capturez l'interface :

<?php

try {
    $result = 10 % 0; // throws a DivisionByZeroError
} catch (Throwable $e) {
    echo get_class($e) . ': ' . $e->getMessage();
}
?>

Résultat :

DivisionByZeroError: Modulo by zero

En règle générale, réservez Exception aux problèmes dont votre application peut se remettre, et laissez Error représenter des bogues à corriger plutôt qu'à capturer.

Sujets connexes

Conclusion

Les exceptions offrent à PHP une façon structurée de gérer les échecs : une fonction throwe quand elle ne peut pas continuer, et l'appelant catche pour récupérer, journaliser ou relancer. Combinez try, catch et finally pour séparer le chemin heureux de la gestion des erreurs et du nettoyage, utilisez des classes personnalisées pour modéliser les échecs de votre domaine, et n'oubliez pas que les problèmes au niveau du moteur arrivent sous forme d'Error (capturable via Throwable). Pratiquer ces patterns dans vos propres projets rendra votre code bien plus robuste.

Pratique

Pratique
Qu'est-ce qui est vrai à propos des exceptions PHP selon les informations de l'URL fournie ?
Qu'est-ce qui est vrai à propos des exceptions PHP selon les informations de l'URL fournie ?
Was this page helpful?