web-dev-qa-db-fra.com

MySQLi a préparé des rapports d'erreurs

J'essaie de comprendre MySQli et je suis confus par le rapport d'erreur. J'utilise la valeur de retour de l'instruction MySQLi 'prepare' pour détecter les erreurs lors de l'exécution de SQL, comme ceci:

$stmt_test =  $mysqliDatabaseConnection->stmt_init();
if($stmt_test->prepare("INSERT INTO testtable VALUES (23,44,56)"))
{
 $stmt_test->execute();
 $stmt_test->close();
}
else echo("Statement failed: ". $stmt_test->error . "<br>");

Mais, la valeur de retour de l'instruction prepare détecte-t-elle uniquement s'il y a une erreur dans la préparation de l'instruction SQL et ne détecte-t-elle pas les erreurs d'exécution? Si c'est le cas, je dois donc modifier ma ligne d'exécution pour signaler les erreurs ainsi:

if($stmt_test->execute()) $errorflag=true;

Et puis, pour être en sécurité, dois-je également faire ce qui suit après l'exécution de la déclaration:

if($stmt_test->errno) {$errorflag=true;}

... Ou étais-je d'accord pour commencer et la valeur de retour sur l'instruction MySQLi prepare 'capture toutes les erreurs associées à l'exécution complète de la requête qu'elle définit?

Merci C

57
Columbo

J'ai écrit cela deux fois auparavant au cours des deux derniers jours (donc pour moi, c'est un doublon même si les questions ont commencé un peu différemment).

Chaque méthode de mysqli peut échouer. Vous devez tester chaque valeur de retour. Si l'on échoue, demandez-vous s'il est logique de continuer avec un objet qui n'est pas dans l'état auquel vous vous attendez. (Potentiellement pas dans un état "sûr", mais je pense que ce n'est pas un problème ici.)

Étant donné que seul le message d'erreur de la dernière opération est stocké par connexion/instruction, vous risquez de perdre des informations sur la cause de l'erreur si vous continuez après que quelque chose s'est mal passé. Vous pouvez utiliser ces informations pour laisser le script décider de réessayer (uniquement un problème temporaire), de modifier quelque chose ou de renflouer complètement (et de signaler un bogue). Et cela facilite le débogage.

$stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
// prepare() can fail because of syntax errors, missing privileges, ....
if ( false===$stmt ) {
  // and since all the following operations need a valid/ready statement object
  // it doesn't make sense to go on
  // you might want to use a more sophisticated mechanism than die()
  // but's it's only an example
  die('prepare() failed: ' . htmlspecialchars($mysqli->error));
}

$rc = $stmt->bind_param('iii', $x, $y, $z);
// bind_param() can fail because the number of parameter doesn't match the placeholders in the statement
// or there's a type conflict(?), or ....
if ( false===$rc ) {
  // again execute() is useless if you can't bind the parameters. Bail out somehow.
  die('bind_param() failed: ' . htmlspecialchars($stmt->error));
}

$rc = $stmt->execute();
// execute() can fail for various reasons. And may it be as stupid as someone tripping over the network cable
// 2006 "server gone away" is always an option
if ( false===$rc ) {
  die('execute() failed: ' . htmlspecialchars($stmt->error));
}

$stmt->close();

edit: juste quelques notes six ans plus tard ....
L'extension mysqli est parfaitement capable de signaler les opérations qui entraînent un code d'erreur (mysqli) autre que 0 via des exceptions, voir mysqli_driver :: $ report_mode .
die () est vraiment, vraiment grossier et je ne l'utiliserais même plus pour des exemples comme celui-ci.
Donc, s'il vous plaît, supprimez seulement le fait que chaque opération (mysql) peut échoue pour un certain nombre de raisons; même si exactement la même chose s'est bien passée mille fois avant ....

118
VolkerK

exhaustivité

Vous devez vérifier les deux $mysqli et $statement. S'ils sont faux, vous devez générer $mysqli->error ou $statement->error respectivement.

Efficacité

Pour les scripts simples qui peuvent se terminer, j'utilise de simples lignes simples qui déclenchent une erreur PHP avec le message. Pour une application plus complexe, un système d'avertissement d'erreur doit être activé à la place, par exemple en lançant une exception.

Exemple d'utilisation 1: script simple

# This is in a simple command line script
$mysqli = new mysqli('localhost', 'buzUser', 'buzPassword');
$q = "UPDATE foo SET bar=1";
($statement = $mysqli->prepare($q)) or trigger_error($mysqli->error, E_USER_ERROR);
$statement->execute() or trigger_error($statement->error, E_USER_ERROR);

Exemple d'utilisation 2: Application

# This is part of an application
class FuzDatabaseException extends Exception {
}

class Foo {
  public $mysqli;
  public function __construct(mysqli $mysqli) {
    $this->mysqli = $mysqli;
  }
  public function updateBar() {
    $q = "UPDATE foo SET bar=1";
    $statement = $this->mysqli->prepare($q);
    if (!$statement) {
      throw new FuzDatabaseException($mysqli->error);
    }

    if (!$statement->execute()) {
      throw new FuzDatabaseException($statement->error);
    }
  }
}

$foo = new Foo(new mysqli('localhost','buzUser','buzPassword'));
try {
  $foo->updateBar();
} catch (FuzDatabaseException $e)
  $msg = $e->getMessage();
  // Now send warning emails, write log
}
15
cmc

Je ne sais pas si cela répond à votre question ou non. Désolé sinon

Pour obtenir l'erreur signalée par la base de données mysql à propos de votre requête, vous devez utiliser votre objet de connexion comme focus.

alors:

echo $mysqliDatabaseConnection->error

ferait écho à l'erreur envoyée par mysql à propos de votre requête.

J'espère que ça t'as aidé

4
andyface