[PHP] PDO::exec,query,executeの違い

SQLクエリを実行する関数について、
複数あるので、その違いをまとめてみた。

○exec

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

一度の関数コールで SQL 文を実行し、
文によって作用した行数を返す。

“insert”、”delete”など、
SQL 文の実行で完結する場合に使える。

○query

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

SQL ステートメントを実行し、
結果セットを PDOStatement オブジェクトとして返す。

“select”などで、返ってきたデータを活用する場合には、
“exec”は使えないので、こっちを使う。

●PDOStatement:http://php.net/manual/ja/class.pdostatement.php

○execute

http://php.net/manual/ja/pdostatement.execute.php

プリペアドステートメントを実行する。

クエリ文中の要素をパラメータにして代入したりできるので、
クエリを動的に実行したい時などに向いている。

これらを使って、プログラムを作ってみる。

準備

○テスト用のデータベース・ユーザーの作成

mysql> create database test;
mysql> create table test (id int primary key auto_increment, name varchar(10));
mysql> create user testuser@localhost
    -> identified by 'password';
mysql> grant all on test.* to testuser@localhost;

○includeする関数の準備

データベース接続用、エスケープ用の関数は
独習PHPのサンプルソースをそのまま借用。

・DbManager.php(DB接続パラメータだけは変更)

<?php
function getDb() {
  $dsn = 'mysql:dbname=test; host=127.0.0.1; charset=utf8';
  $usr = 'testuser';
  $passwd = 'password';

    $db = new PDO($dsn, $usr, $passwd);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    //$db = new PDO($dsn, $usr, $passwd, [PDO::ATTR_PERSISTENT => true);
  return $db;
}

・Encode.php

<?php
function e(string $str, string $charset = 'UTF-8'): string {
  return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, $charset);
}

作成

○データを挿入し、結果を表示するプログラム。
・insert.php

<?php
require_once 'DbManager.php';
require_once 'Encode.php';

$query1 = "INSERT INTO test (name) VALUES ('test1')";
$query2 = "SELECT * from test";

try {
    $db = getDb();
    $stt1 = $db->exec($query1);
    $stt2 = $db->query($query2);
?>

<!DOCTYPE html>
<html>
<head><title>PHP TEST INSERT</title></head>
<body>
<h3>データを挿入しました</h3>

<table border=1>
  <th>id</th><th>名前</th>
<?php
        while($row = $stt2->fetch(PDO::FETCH_ASSOC)){
?>
  <tr>
    <td><?=e($row['id'])?></td>
    <td><?=e($row['name'])?></td>
  </tr>
<?php
        }
?>
</table>
</body>
</html>

<?php
} catch(PDOException $e) {
    print "エラーメッセージ:{$e->getMessage()}";
} finally {
    $db = null;
}

○実行結果

F5を押すと行数が増えてくっていう、
シュールなプログラムになりましたw

でも実際は、挿入するデータも、
フォームから受け取ったデータだったりするので、
executeを使う方が現実的。

・insert2.php

<?php
require_once 'DbManager.php';
require_once 'Encode.php';

$name = 'test1';
// $name = e($_POST['name']);

$query1 = "INSERT INTO test (name) VALUES (:name)";
$query2 = "SELECT * from test where id=:id";

try {
    $db = getDb();

    $stt1 = $db->prepare($query1);
    $stt1->bindValue(':name', $name);
    $stt1->execute();

    $insert_id = $db->lastInsertId();

    $stt2 = $db->prepare($query2);
    $stt2->bindValue(':id', $insert_id);
    $stt2->execute();

    $row = $stt2->fetch(PDO::FETCH_ASSOC);

} catch(PDOException $e) {
    print "エラーメッセージ:{$e->getMessage()}";
} finally {
    $db = null;
}
?>

<!DOCTYPE html>
<html>
<head><title>PHP TEST INSERT</title></head>
<body>
<h3>データを挿入しました</h3>
挿入したデータは以下の通りです。

<table border=1>
  <th>id</th><th>名前</th>
  <tr>
    <td><?=e($row['id'])?></td>
    <td><?=e($row['name'])?></td>
  </tr>
</table>

</body>
</html>

○実行結果

多分、こっちの場合の方が多いですね。
結果の表示も、挿入したデータだけにできました。
(クエリ文を’.’でつなげたりして作るのは好ましくなく、
動的なクエリ文の場合は、プレイスホルダで記述すべきとのこと)

また、削除とかの場合は、
削除するデータを指定してあげることがほとんどだと思うので、
このやり方を使う方が多いでしょう。

・delete.php

<?php
require_once 'DbManager.php';
require_once 'Encode.php';

$query1 = 'SELECT * from test where id=:id';
$query2 = 'DELETE from test where id=:id';

$id = 1;
// $id = e($_POST['id']);

try {
    $db = getDb();

    $stt1 = $db->prepare($query1);
    $stt1->bindValue(':id', $id);
    $stt1->execute();

    $row = $stt1->fetch(PDO::FETCH_ASSOC);

    $stt2 = $db->prepare($query2);
    $stt2->bindValue(':id', $id);
    $stt2->execute();

} catch(PDOException $e) {
    print "エラーメッセージ:{$e->getMessage()}";
} finally {
    $db = null;
}
?>

<!DOCTYPE html>
<html>
<head><title>PHP TEST DELETE</title></head>
<body>
<h3>データを削除しました</h3>
削除したデータは以下の通りです。

<table border=1>
  <th>id</th><th>名前</th>
  <tr>
    <td><?=e($row['id'])?></td>
    <td><?=e($row['name'])?></td>
  </tr>
</table>

</body>
</html>

○実行結果

そんな感じで、insert,select,update,deleteでは、
prepare->executeを使う場合が多いんですかね?

ただ、必要ない場合は、exec等を使った方が、
ソースが短くてスッキリするのかなと・・・

独習PHP 第3版

コメントを残す

メールアドレスが公開されることはありません。