LoginSignup
0
0

More than 1 year has passed since last update.

【PHP/SQL】SELECT count(*) 実行時の戻り値パターンと条件分岐

Last updated at Posted at 2022-09-19

現在エンジニアを目指して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))1trueを表しているようです。
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

エラーメッセージが出てくるようになりました。
こういうことですよね?

※内容や考え方に間違い、補足等ありましたらぜひ教えていただけますと幸いです!

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0