😃
プリペアドステートメントの出力(ログ,デバッグ用)
悩み
ログ用に出すのもそうだし、SQLでエラーが出た際に
実際にDBに発行されているSQLの内容を調べる方法がわからなかった。
変数がバインドされた後に実際に投げられているSQLはどうやって調べるの、という疑問があった。
結論
私はこのように出しました。
私の環境(PHP8.2.9 mysql 5.7.36)では動きました。
//バインドされた後のプリペアドステートメントを出力(ログ用)
public function getPreparedStmtAfterBind($pdo_stmt) {
ob_start();
$pdo_stmt->debugDumpParams();
$content = ob_get_contents();
ob_end_clean();
preg_match('/Sent\sSQL:\s\[\d+\]\s(.*?)\sParams/s', $content, $matches);
return $matches[1];
}
使用方法
引数にはPDOに対してprepare($sql)をして、executeした時の戻り値である変数を指定
$stmt = $pdo->prepare($sql);
$result = $stmt->execute($params);
echo getPreparedStmtAfterBind($result);
とすれば帰ってくるはずです。
やっていること
- ob_start()で出力バッファリング
- PDOStatementインスタンス(上の例だと$result)に対してdebugDumpParamsメソッドを実行
- 2の実行結果を変数contentに格納
- ob_end_clean()でバッファをクリアして終了
- contentの中からpreg_matchでほしいところだけ抽出
- その結果を出力
出力バッファリング周りについてはこの方を参考にしました。
経緯
よくPHPでSQLを投げる際、
$stmt = $pdo->prepare($sql);
した後に
$stmt->execute($params);
とかするのですが、
たまにエラーになることがよくあります。
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
与えた変数の数と、バインド変数の数があっていませんよ、というエラーです。
たいてい、
いやそんなことはない。あってるはずだ。
と思いながらデバッグを始めるんですけど。
実際にDBに発行されているSQL文って、ぱっとは出せないんですよね。
prepareメソッドを実行する際に引数として与える sql文を 出力して
埋め込む変数を1つずつechoなり var_dumpすれば見えなくもないですが、
見ずらい、めんどくさい
そこでなんとかして、出せないかといろいろ探していたところ
と思ったのですが、出力がまぁかゆいところに手が届かない、出力でした。
SQL: [322] UPDATE
user
SET
name = :name,
email = :email,
sex_type = :sex_type,
age_type = :age_type,
update_at = now()
, icon_image_file = :icon_image_file WHERE id = :id
Sent SQL: [358] UPDATE
user
SET
name = 'あたし',
email = '**************************',
sex_type = '0',
age_type = '4',
update_at = now()
, icon_image_file = '*************************' WHERE id = '**'
Params: 6
Key: Name: [5] :name
paramno=-1
name=[5] ":name"
is_param=1
param_type=2
Key: Name: [6] :email
paramno=-1
name=[6] ":email"
is_param=1
param_type=2
Key: Name: [9] :sex_type
paramno=-1
name=[9] ":sex_type"
is_param=1
param_type=2
Key: Name: [9] :age_type
paramno=-1
name=[9] ":age_type"
is_param=1
param_type=2
Key: Name: [16] :icon_image_file
paramno=-1
name=[16] ":icon_image_file"
is_param=1
param_type=2
Key: Name: [3] :id
paramno=-1
name=[3] ":id"
is_param=1
param_type=2
欲しいのは
Sent SQL: [358] UPDATE
user
SET
name = 'あたし',
email = '**************************',
sex_type = '0',
age_type = '4',
update_at = now()
, icon_image_file = '*************************' WHERE id = '**'
この中の UPDATE から PARAMSの間なんですよね。
だから、preg_match()で抜き出しました。
正直、参考にした方の記事が無かったら思いつきませんでしたね。
ありがとうございます。
結果はこんな感じです。
UPDATE user SET name = 'あたし',email = '**************************', sex_type = '0',age_type = '4',update_at = now(), icon_image_file = '*************************' WHERE id = '**'
ちなみに、php自体は初心者なのでおかしな箇所があるかもしれません。
その時はご指摘ください。
Discussion