web-dev-qa-db-ja.com

MySQLiプリペアドステートメントのエラー報告

私はMySQliを回避しようとしていますが、エラー報告に混乱しています。次のように、SQLiの実行時にエラーを検出するために、MySQLiの「prepare」ステートメントの戻り値を使用しています。

$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>");

しかし、prepareステートメントの戻り値は、SQLステートメントの準備にエラーがあるかどうかを検出するだけで、実行エラーは検出しませんか?もしそうなら、このようにエラーにフラグを立てるように実行行を変更する必要があります:

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

そして、念のために、ステートメントの実行後に次のことも行う必要があります。

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

...それとも、始めてOKで、MySQLi prepare 'ステートメントの戻り値は、定義するクエリの完全な実行に関連するすべてのエラーをキャプチャしますか

ありがとうC

57
Columbo

私はこれを過去2日間に2回書いた(そのため、質問が少し異なって始まったとしても、私にとっては重複している)。

Mysqliの各メソッドは失敗する可能性があります。各戻り値をテストする必要があります。失敗した場合は、期待する状態にないオブジェクトを続行することが理にかなっているかどうかを考えてください。 (潜在的に「安全な」状態ではありませんが、ここでは問題ではないと思います。)

接続/ステートメントごとに最後の操作のエラーメッセージのみが保存されるため、何かが間違った後に続行すると、whatエラーの原因に関する情報を失う可能性があります。その情報を使用して、スクリプトに再試行(一時的な問題のみ)、変更、または完全に救済(およびバグの報告)するかどうかを判断させることができます。また、デバッグがはるかに簡単になります。

$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();

編集:6年後のほんの数音…。
mysqli拡張機能は、例外を介して0以外の(mysqli)エラーコードを生成する操作を完全にレポートできます。 mysqli_driver :: $ report_mode .
die() は本当に粗雑で、このような例でも使用しません。
だから、each and every(mysql)操作canいくつかの理由で失敗します。偶数ifまったく同じことが以前にも千回うまくいった....

118
VolkerK

完全性

$mysqli$statementの両方を確認する必要があります。 falseの場合、それぞれ$mysqli->errorまたは$statement->errorを出力する必要があります。

効率

終了する可能性のある単純なスクリプトの場合、メッセージでPHPエラーをトリガーする単純なワンライナーを使用します。より複雑なアプリケーションの場合は、代わりに例外。

使用例1:簡単なスクリプト

# 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);

使用例2:アプリケーション

# 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

これがあなたの質問に答えるかどうかわからない。そうでない場合は申し訳ありません

クエリについてmysqlデータベースから報告されたエラーを取得するには、接続オブジェクトをフォーカスとして使用する必要があります。

そう:

echo $mysqliDatabaseConnection->error

クエリに関してmysqlから送信されたエラーをエコーし​​ます。

役立つことを願っています

4
andyface