W3docs

try

Apprenez comment PHP try/catch/finally gère les exceptions. Couvre les blocs catch multiples, les types union, le rethrow et les pièges courants.

Le mot-clé PHP try

Le mot-clé try marque un bloc de code susceptible de lever une exception — un objet signalant que quelque chose s'est mal passé et que l'exécution normale ne peut pas continuer. Lorsqu'une exception est levée à l'intérieur d'un bloc try, PHP arrête d'exécuter le reste de ce bloc et recherche un bloc catch correspondant pour la gérer. Un bloc finally optionnel s'exécute ensuite, quoi qu'il se soit passé.

Cette page couvre la syntaxe try/catch/finally, la façon dont plusieurs blocs catch sont mis en correspondance, la capture de plusieurs types d'exceptions à la fois, le rethrow, et les pièges qui font trébucher les développeurs. Si vous êtes novice en matière de levée d'erreurs, lisez d'abord Les exceptions en PHP.

Syntaxe

try {
  // Code that may throw an exception
} catch (ExceptionType $e) {
  // Code that runs if an exception of ExceptionType (or a subclass) is thrown
} finally {
  // Optional: always runs, whether or not an exception was thrown
}

Un bloc try doit être suivi d'au moins un bloc catch, ou d'un bloc finally, ou des deux — un try seul est une erreur de syntaxe. La variable dans catch (ExceptionType $e) contient l'objet exception levé, que vous interrogez avec des méthodes telles que $e->getMessage().

Premier exemple

La fonction ci-dessous lève une exception lorsqu'on lui demande de diviser par zéro. Le bloc try l'appelle, le bloc catch signale le problème, et finally s'exécute toujours :

<?php

function divide($dividend, $divisor)
{
  if ($divisor == 0) {
    throw new Exception("Cannot divide by zero.");
  }
  return $dividend / $divisor;
}

try {
  $result = divide(10, 0);
  echo $result;            // skipped — divide() threw before returning
} catch (Exception $e) {
  echo "Error: " . $e->getMessage() . PHP_EOL;
} finally {
  echo "Done." . PHP_EOL;
}

Résultat :

Error: Cannot divide by zero.
Done.

Remarquez que echo $result; ne s'exécute jamais : dès que divide(10, 0) lève une exception, le contrôle saute directement au bloc catch. Le bloc finally s'exécute ensuite. Si vous appelez divide(10, 2) à la place, aucune exception n'est levée, le bloc try affiche 5, et finally affiche quand même Done..

Plusieurs blocs catch

Un seul try peut être suivi de plusieurs blocs catch. PHP les vérifie de haut en bas et exécute le premier dont le type correspond à l'exception levée (la correspondance inclut les sous-classes). Listez les types plus spécifiques avant les types plus généraux — un catch (Exception $e) en tête avalerait tout ce qui suit.

<?php

try {
  $value = "5";
  if (!is_int($value)) {
    throw new TypeError("Expected an integer.");
  }
} catch (TypeError $e) {
  echo "Type problem: " . $e->getMessage() . PHP_EOL;
} catch (Exception $e) {
  echo "Other problem: " . $e->getMessage() . PHP_EOL;
}

Résultat :

Type problem: Expected an integer.

Capturer plusieurs types dans un seul bloc

Lorsque deux types d'exceptions doivent être gérés de la même façon, combinez-les avec une barre verticale (|) — une fonctionnalité ajoutée dans PHP 7.1 — plutôt que de dupliquer le bloc :

<?php

try {
  throw new RuntimeException("Network timed out.");
} catch (RuntimeException | LogicException $e) {
  echo "Handled: " . $e->getMessage() . PHP_EOL;
}

Résultat :

Handled: Network timed out.

Comportement de finally

Le bloc finally s'exécute même si le bloc try ou catch exécute un return. C'est donc le bon endroit pour le nettoyage — fermeture de fichiers, libération de verrous, annulation d'une transaction — qui doit avoir lieu sur chaque chemin d'exécution :

<?php

function readConfig()
{
  try {
    return "config loaded";
  } finally {
    echo "Cleanup ran." . PHP_EOL;
  }
}

echo readConfig() . PHP_EOL;

Résultat :

Cleanup ran.
config loaded

Le bloc finally s'exécute avant que la fonction retourne réellement sa valeur. Évitez de retourner depuis finally lui-même : un return là-dedans remplace la valeur de try/catch et écarte silencieusement toute exception en cours de propagation.

Rethrow d'une exception

Un bloc catch peut effectuer un travail partiel — journaliser l'erreur, ajouter du contexte — puis relancer l'exception afin qu'un appelant plus haut dans la pile puisse décider quoi faire. Utilisez throw $e; pour relancer le même objet :

<?php

try {
  try {
    throw new Exception("Disk full.");
  } catch (Exception $e) {
    echo "Logging: " . $e->getMessage() . PHP_EOL;
    throw $e; // hand it to the outer handler
  }
} catch (Exception $e) {
  echo "Outer handler: " . $e->getMessage() . PHP_EOL;
}

Résultat :

Logging: Disk full.
Outer handler: Disk full.

Pièges courants

  • try a besoin d'un partenaire. Un bloc try seul ne se parse pas — associez-le à au moins un catch ou un finally.
  • Les erreurs ne sont pas toutes des exceptions. De nombreux avertissements d'exécution (une variable non définie, un fopen() échoué) ne sont pas levés comme des exceptions, donc catch ne les verra pas. Utilisez set_error_handler() ou vérifiez les valeurs de retour pour ceux-là. Les objets Error fatals (comme TypeError) peuvent être capturés car ils implémentent Throwable.
  • Ordonnez vos blocs catch du plus spécifique au plus général. Un large catch (Exception $e) placé en premier masque tous les blocs suivants.
  • N'avalez pas silencieusement les erreurs. Un bloc catch vide dissimule l'échec ; journalisez au minimum $e->getMessage() pour que le problème soit visible.
  • finally peut masquer les exceptions. Retourner depuis finally écarte à la fois la valeur de retour de try et toute exception en vol.

Quand utiliser try ?

Recourez à try/catch lorsqu'un échec est exceptionnel et que le code appelant peut raisonnablement y réagir : une connexion à la base de données qui se coupe, une API qui retourne une erreur, une saisie utilisateur invalide que vous souhaitez rejeter proprement. Pour un flux de contrôle ordinaire (une clé est-elle présente dans un tableau ? une chaîne est-elle vide ?), utilisez des conditions normales — les exceptions sont faites pour le chemin anormal, pas pour la ramification quotidienne.

Voir aussi

Pratique

Pratique
Quelle balise est utilisée en PHP pour démarrer un bloc de code ?
Quelle balise est utilisée en PHP pour démarrer un bloc de code ?
Was this page helpful?