プリペアドステートメントの出力(ログ,デバッグ用)

# 悩み
ログ用に出すのもそうだし、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);
    とすれば帰ってくるはずです。
    
```

# やっていること
1. ob_start()で出力バッファリング
2. PDOStatementインスタンス(上の例だと$result)に対してdebugDumpParamsメソッドを実行
3. 2の実行結果を変数contentに格納
4. ob_end_clean()でバッファをクリアして終了
5. contentの中からpreg_matchでほしいところだけ抽出
6. その結果を出力

出力バッファリング周りについてはこの方を参考にしました。
https://servercan.net/blog/2021/03/pdo%E3%81%A7%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%9Fsql%E6%96%87%E3%82%92debugdumpparams%E3%81%8B%E3%82%89%E6%8A%BD%E5%87%BA%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B/


 

# 経緯
よく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すれば見えなくもないですが、

**見ずらい、めんどくさい**

そこでなんとかして、出せないかといろいろ探していたところ
https://www.php.net/manual/ja/pdostatement.debugdumpparams.php
という求めていたものを見つけた！！
と思ったのですが、出力がまぁかゆいところに手が届かない、出力でした。

```
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自体は初心者なのでおかしな箇所があるかもしれません。
その時はご指摘ください。