現在エンジニアを目指してPHPを学習中です。
SQL実行結果の分岐を正しく記述できるようになるべく、
戻り値を確認したので、メモ。
※2022.10.2追記
内容の誤りをご指摘いただき、修正しました。
@takaram さんありがとうございました!
前提
以下のコードを実行しました。
DBカラム名等の細かい部分は本筋と関係ないため略します。
$dbh = new PDO(hoge);
$sql = 'SELECT count(*) FROM table WHERE column = hogehoge';
//DBのオプションは下記(正直PDOオブジェクトをはじめ、下記設定の意味はまだよく分かってません、、)
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
//SQL実行、結果を$resultに
$stmt = $dbh->prepare($sql);
$stmt->execute;
$result = $stmt -> fetch (PDO::FETCH_ASSOC);
//結果を測定
var_dump($result);
error_log(print_r($result,true));
error_log(print_r($result));
先に結論:false値と文字列型の値による分岐が◎
改めて今回の目的は、SQL実行結果の分岐の正しい記述方法。
処理フローとしては以下のかたちがよさそうです。
if($result === false){
//パターン3,SQLエラー
}
if(array_shift($result) === '0'){
//パターン2,該当レコードなし
}else{
//パターン1,該当レコードあり
}
パターン別実行結果
※2022.10.2追記
以下記載のprint_r($result)
について、戻り値がtrueになるのは仕様です。
//公式より
print_r(mixed $value, bool $return = false): string|bool
//return パラメータが true の場合は、 この関数は string を返します。
//それ以外の場合の戻り値は true です。
参照:https://www.php.net/manual/ja/function.print-r.php
1.SQL実行、合致するデータが1つ
・var_dump($result)の値:
クエリ成功:
array(1) { ["count(1)"]=> string(1) "1" } Array ( [count(1)] => 1 )
・print_r($result,true)の値:
[count(1)] => 1
・print_r($result)の値:
1
2.SQL実行、該当データがない
・var_dump($result)の値:
クエリ成功:
array(1) { ["count(1)"]=> string(1) "0" } Array ( [count(1)] => 0 )
・print_r($result,true)の値:
[count(1)] => 0
・print_r($result)の値:
1
3.クエリにミスがありエラー
・var_dump($result)の値:
false:
bool(false)
・print_r($result,true)の値:
(記載なし)
・print_r($result)の値:
1
考察
まず、$resultの結果は以下のような分岐らしい。
SQL実行
└---true---string(1) "1(該当データ数)"(パターン1)
└--string(1) "0"(パターン2)
└---false(パターン3)
SQLが実行された後の結果がstring型として返ってくることも踏まえ、
考えた処理フローが冒頭のもの。
if($result === false){
//パターン3,SQLエラー
}
if(array_shift($result) === '0'){
//パターン2,該当レコードなし
}else{
//パターン1,該当レコードあり
}
考察2(おまけ)
※本題からはやや逸れるので少しダラダラ書きます。
今回試したいずれのパターンでも
error_log(print_r($result))の結果は '1'
になりました。
分岐の条件に用いることができないのはもちろんですが、
値がないはずの実行結果 false の場合でも 1 が表示されるのはおかしいはず、、、
※2022.10.2追記
ここから先の内容は全て誤りです。1が表示されるのは、仕様です。
下記記載のPDO::ERROMODEはSILENCEのままで分岐に問題ありません。
ということで、確認してみました。
var_dump(print_r($result));
//結果:どのパターンでも 'bool(true)'
error_log(print_r($result))
の1
はtrue
を表しているようです。
booleen型ということは、SQL実行の成否のことでは??
だとしたら、false の場合でも true になっているのはなぜ??
はい、怪しいヤツ見つけました。
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT
この設定は、エラーメッセージを出力しないらしい。
情報は持ってるのに、「聞かれてないから」とか言って共有しないタイプのヤツ。
発生したエラーがスルーされている
(本来 false なのに true として処理されている)
ということではなかろうか。
なので、以下の設定に変更。
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
結果
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax
SQLSTATE[42S02]: Base table or view not found
エラーメッセージが出てくるようになりました。
こういうことですよね?
※内容や考え方に間違い、補足等ありましたらぜひ教えていただけますと幸いです!