質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

PHP PDOを使用する

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,062

tanukitii

score 46

PHPでMySQL付近の勉強をしようと思いました。PDOクラスを使おうと思い,コードを書いてみたのですが,うまくいかない部分があり,詰まってしまいました。

<?php
try{
    $db = new PDO('mysql:dbname = mydb; host = 127.0.0.1; charset = utf8', '△△△', '〇〇〇');
}catch(PDOException $e){
    echo "DB接続エラー:". $e->getMessage();
}

 $count = $db->exec('INSERT INTO my_items SET maker_id=1, item_name="もも", price=210, keyword="缶詰,ピンク,甘い", sales=0');
 echo $count . '件のデータを挿入しました。';
?>

出力結果は
件のデータを挿入しました。

で,countの値が表示されません。本来なら入力したSQL文の数ぶん(今回は1)が返ると思うのですが,何も表示されないのです。
いろいろ調べてはみたのですが,PHPのverが7以上であればphp.iniをいじらなくてもPDOは使えますし,コードの間違いも特に見当たらなくどうしたものかと悩んでおります。
ご助言いただけると幸いです。

【追記】
下記のようにコードを修正しても現状は変わらずです。

<?php
try{
    $db = new PDO('mysql:dbname = mydb; host = 127.0.0.1; charset = utf8', '△△', '〇〇');
    $count = $db -> prepare('INSERT INTO my_items SET maker_id=1, item_name="モモ", price=210, keyword="缶詰,ピンク,甘い", sales=0');
    $count -> execute();
}catch(PDOException $e){
    echo "DB接続エラー:". $e->getMessage();
}
?>


・host=localhostにしても何も変わらず。

・phpを実行している手順は上記のコードを
C:\xampp/\htdocs/memo下におき,検索エンジン(chrome)で
http://localhost/memo/index.phpと入力しています。

・php 7.2.11,phpMyAdmin 4.8.3,Apache 2.4.35をWindows10 64bitで使用しています。

・エディタはVSコードを使用しています。

・DBに入力したcreate分は

INSERT INTO my_items SET maker_id=1, item_name="リンゴ", price=210, keyword="缶詰,ピンク,甘い", sales=0


です。これはDB上で実行するとDB上にデータが追加されます。

以上でございます。何卒よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+6

☓ false チェックをするのが普通
○ false チェックをしなくてもいいようにエラーモードを変更するのが普通

PHPでデータベースに接続するときのまとめ - Qiita

ツッコミどころ多すぎるので修正後のコードだけ書いておきます。

<?php

try {

    $pdo = new PDO(
        'mysql:dbname=mydb;host=127.0.0.1;charset=utf8mb4',
        '△△',
        '〇〇',
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]
    );

    $stmt = $pdo->prepare('INSERT INTO my_items(maker_id, item_name, price, keyword, sales) VALUES (?, ?, ?, ?, ?)');
    $stmt->execute([1, 'リンゴ', 210, '缶詰,ピンク,甘い', 0]);

    $count = $stmt->rowCount();
    var_dump($count);

} catch (PDOException $e) {

    echo $e->getMessage();

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/20 18:56

    ありがとうございます。上記のコードでできました。
    PDOの4つ目の引数は別になくてもDBにデータを追加できたのでSQL文が原因ということになりますよね?以前,書籍で学んだとおりにSQL文を書いて,そのときはうまくいっていたのですが,書き方がかわったのでしょうか…マニュアルにそれらしきものが見つからないですし…

    その多すぎるつっこみどころが何かを教えていただければうれしいのですが…。
    申し訳ないです。何卒よろしくお願いします。

    キャンセル

  • 2018/10/20 19:49

    ```
    <?php
    try{
    $db = new PDO('mysql:dbname = mydb; host = 127.0.0.1; charset = utf8', '△△', '〇〇');
    $count = $db -> prepare('INSERT INTO my_items SET maker_id=1, item_name="モモ", price=210, keyword="缶詰,ピンク,甘い", sales=0');
    $count -> execute();
    }catch(PDOException $e){
    echo "DB接続エラー:". $e->getMessage();
    }
    ?>
    ```

    上記のコードに関してもっとも致命的な場所は

    ・PDOの第1引数のDSNは、=の前後にスペースを入れてはならない

    これですね。これのせいで接続の段階で失敗しているはずです。PDOException 飛んでませんかね?接続に関するエラーに関してはエラーモード変更しなくても飛ぶはずなんですが。そのほか、動作に支障は無いが直したほうがいい点を挙げると

    ・MySQL を使う場合は utf8 ではなく utf8mb4 を基本的に選ぶべき
    ・エラーモードは PDO::ERRMODE_EXCEPTION に設定しておくべき
    ・INSERT...SET... はMySQLの独自構文なのでできればSQL標準の INSERT...VALUES... を使うべき
    ・prepare する際には、文字列などの具体値は直接書かずに「?」で入れておいて、execute や bindValue で渡すべき
    ・prepare の返り値の変数名として $count はおかしい。整数ではなく PDOStatement オブジェクト
    ・PHP閉じタグの「?>」は省略できる場合は省略推奨

    など

    キャンセル

  • 2018/10/20 20:01

    知らないことばかりでした…。こんなにも短いコードにこれだけの問題点があるのですね。
    とても勉強になりました。

    多くの方から,ご助言をいただきましたが,”問題が解決した”,”私のコードの問題点を多くあげていただいた”という理由でmpywさんをベストアンサーにいたします。
    誠にありがとうございます。

    キャンセル

+2

if($count === false) { echo "failed"; }

件数の出力前にチェックをしてください。

マニュアルを参考に

http://php.net/manual/ja/pdo.exec.php

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/20 09:10

    ご回答ありがとうございます。
    これを付け加えるのは普通でしたか…勉強不足でしたね…
    参考になりました。

    キャンセル

+2

2点ご確認を。

  1. そのSQL本当に実行できてる?DBに直接実行して想定通りの結果になるか?
    また、プログラムから利用した場合、今回はINSERTなので利用後にDBを確認して想定通りのデータが追加されているか
    コードに間違いがなくても正しくSQLが実行されないと想定通りの結果は得られませんよね。SQLもPHPからしたら外部の機能ですが「コード」です。
  2. try-catchで接続だけ監視しても意味がないのでは。
    SQLが正しく実行できるかどうかはPHP側は知らないので「確実に正しい結果が返ってくる」という保証はどこにもないはずです。
    せっかくPDOException を捕捉しているのですから接続→実行→結果まで全て入れてあげましょう。そうしたら何かエラーを捉えてくれるかもしれません。
    でも現状の書き方だとexec()における異常を検知できません。

本来なら入力したSQL文の数ぶん(今回は1)が返ると思うのですが,

「思う」は大変危険な考え方です。
プログラムは指示したとおりにしか動きません。0か1かの世界です(成功か失敗か)
「想定通りに動いていない」ということは、制作者がその指示を失敗しているにすぎません。

こういうときはデバッグです。
変数 をvar_dump()で出力してみてください。なぜ画面上に何も表示されないのかが見えてくるかと思います。

また、exec()のPHPマニュアルには下記のようにあります。

PDO::exec() は、発行した SQL ステートメントによって更新もしくは 削除された行数を返します。 1 行も作用しなかった場合、PDO::exec() は 0 を返します。 
警告
この関数は論理値 FALSE を返す可能性がありますが、FALSE として評価される値を返す可能性もあります。 詳細については 論理値の セクションを参照してください。この関数の返り値を調べるには ===演算子 を 使用してください。

ここで「入力したSQL文の数ぶん(今回は1)」という理解が間違っていることがわかるかと思います。
入力したSQLの数ではなく「更新が作用した件数」です。
insertでも1文で複数レコード挿入することができます。

insert into tableA values (1,'test1'),(2,'test2'),(1,'test3')


上記は「1文」ですが、exec()にて成功した場合「3」が返る内容です。

また「警告」のところも読むとわかりますが、必ずしも作用した件数が返るわけではありません。
その辺りは、既に回答に出ている通り、正誤判定を入れた上で利用するのが確実です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • この投稿は削除されました

  • 2018/10/20 10:55

    えっと、質問本文に追記してください。

    キャンセル

  • 2018/10/20 17:11

    申し訳ないです,勘違いしていました。今,本文に追記いたしました。

    キャンセル

+1

リファレンスによれば、executeの戻り値は成功したSQL文の数ではなくて成否(TrueかFalse)が返ります。
http://php.net/manual/ja/pdostatement.execute.php

SQLで作用を及ぼした行数(ここでいえばInsertされた件数)を取得したいのであれば、やはりリファレンスになりますが「rowCount」が使えます。
http://php.net/manual/ja/pdostatement.rowcount.php

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/20 04:39

    exec()を利用されているのでこっちですね。
    http://php.net/manual/ja/pdo.exec.php
    > PDO::exec() は、発行した SQL ステートメントによって更新もしくは 削除された行数を返します。 1 行も作用しなかった場合、PDO::exec() は 0 を返します。

    キャンセル

  • 2018/10/20 09:07

    ご回答誠にありがとうございます。
    rowCountという関数は知らなかったので,今度使用してみることにします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る