web-dev-qa-db-fra.com

PHP try/catch et erreur fatale

J'utilise le script suivant pour utiliser une base de données utilisant PHP:

try{
    $db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}

Maintenant, je veux utiliser ce handle de base de données pour faire une requête en utilisant ce code:

try{
    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(array(
        '...' => $...,
        '...' => $...
    ));
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}

Voici le problème:

  • Lorsque la connexion à la base de données est correcte, tout fonctionne,
  • Lorsque la connexion échoue mais que je n'utilise pas la base de données, j'ai le tableau $GLOBALS['errors'][] et le script est toujours en cours d'exécution par la suite,
  • Lorsque la connexion à la base de données a échoué, l'erreur fatale suivante apparaît:

Remarque: Variable non définie: db dans C:\xampp\htdocs [...]\test.php à la ligne 32

Erreur fatale: appel d'une fonction membre prepare () sur un non-objet dans C:\xampp\htdocs [...]\test.php à la ligne 32

Remarque: La ligne 32 est l'instruction $query = $db->prepare(...).

C'est-à-dire que le script se bloque et que le test/capture semble être inutile. Savez-vous pourquoi ce deuxième essai/attrape ne fonctionne pas et comment le résoudre?

Merci pour l'aide!

EDIT: Il y a de très bonnes réponses. J'ai validé celui qui n'est pas exactement ce que je voulais faire, mais qui est probablement la meilleure approche.

15
Ploppe

Les blocs try/catch ne fonctionnent que pour les exceptions levées (throw Exception ou une sous-classe de Exception doit être appelée). Vous ne pouvez pas détecter les erreurs fatales à l'aide de try/catch.

Si votre connexion à la base de données ne peut pas être établie, je la considérerais comme étant fatale car vous avez probablement besoin que votre base de données fasse quelque chose de significatif sur la page.

PDO lève une exception si la connexion ne peut pas être établie. Votre problème spécifique est que $db n'est pas défini lorsque vous essayez d'appeler une méthode avec cette méthode afin d'obtenir un pointeur null (en quelque sorte) fatal. Plutôt que de parcourir les fonctions de if ($db == null), comme le suggèrent d'autres personnes, vous devez simplement corriger votre code pour vous assurer que $db est toujours défini lorsque vous en avez besoin ou que vous disposez d'un moyen moins fragile de garantir qu'une connexion à une base de données est disponible dans le code qui l'utilise .

Si vous voulez vraiment "attraper" les erreurs fatales, utilisez set_error_handler, mais cela arrête l'exécution du script sur les erreurs fatales.

26
Explosion Pills

En PHP7, nous pouvons maintenant utiliser try catch error fatal avec un travail simple

try {
   do some thing evil
} catch (Error $e) {
   echo 'Now you can catch me!';
}

Mais normalement, nous devrions éviter d'utiliser catch Error, car cela implique de rater le code qui appartient à la responsabilité du programmeur :-)

6
Hiro

Si la connexion à la base de données échoue, $db de votre premier bloc try .. catch sera nul. C'est pourquoi plus tard, vous ne pouvez pas utiliser un membre de non-objet, dans votre cas $db->prepare(...). Avant d'utiliser cet add 

if ($db) {
    // other try catch statement
}

Cela garantira que vous disposez d'une instance de base de données pour l'utiliser.

1
Kosta

Pourquoi utilisez-vous les instructions try ... catch pour déclarer cela? Remplacez ceci:

try{
    $db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}

Avec:

$db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options) or die("Cannot Create PDO!");

Ou à votre façon:

$db = new PDO('mysql:Host='.$Host.';port='.$port.';dbname='.$db, $user, $pass, $options) or ($GLOBALS['errors'][] = "Cannot Create PDO!");

Essayez d’ajouter l’instruction if suivante:

if ($db) {
    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(....);
}
else die('Connection lost');
0
Ertunç

Je ne signalerai pas ce qui a déjà été écrit sur les tests si $db est vide. Ajoutez simplement qu'une solution "propre" consiste à créer artificiellement une exception si la connexion à la base de données échoue:

if ($db == NULL) throw new Exception('Connection failed.');

Insérez la ligne précédente dans le try - catch comme suit:

try{

    // This line create an exception if $db is empty
    if ($db == NULL) throw new Exception('Connection failed.');


    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(array(
        '...' => $...,
        '...' => $...
    ));
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}

J'espère que cela aidera les autres!

0
Imabot
try{
if(!is_null($db))
{
    $query = $db->prepare("INSERT INTO users (...) VALUES (...);");
    $query->execute(array(
        '...' => $...,
        '...' => $...
    ));
}
}
catch(Exception $e){
    $GLOBALS['errors'][] = $e;
}
0
Arun Killu