データベース操作 : PHP

Pocket

最近はフレームワークを利用しPDOを直接意識することはあまりありませんが健忘録として記載します。
PHP 5.1以降はデフォルトでバンドルされています。  

PDO/PDOStatementクラス

PDO::query実行例

<dbname>、<user>、<password>は適宜読み替えてください。

mysql> CREATE DATABASE <database> DEFAULT CHARACTER SET utf8mb4;
CREATE TABLE sample(
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    user VARCHAR(255),
    password VARCHAR(255),
    PRIMARY KEY (id)
);
<?php
// PDOは接続時にエラーが発生したときは例外を投げます。
// 必ずtry catch文を記載します。
// 接続時ではないときのエラーの扱いはPDO::ERRMODEで設定します。
$options = array(
    'PDO::ATTR_PERSISTENT' => true  // 持続的接続
);
try {
    $db = new PDO('mysql:host=localhost;dbname=<dbname>;charset=utf8mb4', '<user>', '<password>', $options);
    $st = $db->query("SELECT * FROM sample", PDO::FETCH_ASSOC);
    foreach($st as $row) {  // PDOStatementはIteratorインターフェース(Traversableインターフェースも)を実装しています。
        echo $row['id'] . ': ' . $row['user'] . '<br>';
    }
} catch (PDOException $e) {
    echo $e->getMessage();
}

プリペアドステートメント

プリペアドステートメントはプレースホルダでSQL文を準備し値をバインドし実行します。

  1. プリペアドステートメントはPDO::prepareで準備します。
    prepareはPDOStatementインスタンスを返します。
  2. プレースホルダへ値をバインドします。
    プレースホルダへ値をバインドする方法はPDOStatement::executeの引数として設定する方法とPDOStatement::bindParamで設定する方法があります。
    bindParamは変数の型を指定できます。bindParamを使わずにexecuteの引数で指定するときは型はPDO::PARAM_STRになります。
  3. 実行します(PDOStatement::execute)。

 プレースホルダ

  • 疑問符プレースホルダ ?
  • 名前付きプレースホルダ :name

疑問符プレースホルダの例

INSERT INTO example (a, b) VALURES(?, ?)

名前付きプレースホルダの例

INSERT INTO example (a, b) VALURES(:a, :b)

プリペアドステートメント実行

プレースホルダーをexecuteの引数でバインド

CREATE TABLE sample(
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    user VARCHAR(255),
    password VARCHAR(255),
    PRIMARY KEY (id)
);
<?php
try {
    $db = new PDO('mysql:host=localhost;dbname=<dbname>;charset=utf8mb4', '<user>', '<password>');
} catch (PDOException $e) {
    echo $e->getMessage();
}

// 疑問符プレースホルダでプリペアドステートメント取得
$st = $db->prepare("INSERT INTO sample (user, password) VALUES(?, ?)");
$result = $st->execute(['foo', 'bar']); // ユーザーfoo, パスワードbar
var_dump($result); // 成功:TURE, 失敗:FALSE
// プリペアドステートメントは準備したSQLを複数回実行できます。
$result = $st->execute(['hoge', 'fuga']); 
var_dump($result); // 成功:TURE, 失敗:FALSE

// 名前付きプレースホルダでプリペアドステートメント取得
$st = $db->prepare("INSERT INTO sample (user, password) VALUES(:user, :password)");
$result = $st->execute(['user' => 'foo2', 'password' => 'baz2']);
var_dump($result); // 成功:TRUE, 失敗:FALSE

$dt = null; // 切断

プレースホルダーをbindParamでバインド

CREATE TABLE example(
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    data LONGBLOB,
    PRIMARY KEY (id)
);

画像をLONGBLOGとしてテーブルへ格納します。

<?php
// 接続に失敗するとPDOExceptionを返します。
try {
    $db = new PDO('mysql:host=localhost;dbname=tutorial;charset=utf8mb4', '<user>', '<password>');
} catch (PDOException $e) {
    echo $e->getMessage();
}
/** @var \PDOStatement $st **/
$st = $db->prepare("INSERT INTO example (data) VALUES(?)");
$fp = fopen('30x30.png', 'rb');
$st->bindParam(1, $fp, PDO::PARAM_LOB); // bindParamを使うことで型を指定しバインドできます。
$st->execute(); // 成功はTRUE, 失敗はFALSEを返します。
$db = null;     // データベースの切断はPDOインスタンスへnullを設定します。

画像を出力します。

<?php
try {
    $db = new PDO('mysql:host=localhost;dbname=tutorial;charset=utf8mb4', '<user>', '<password>');
} catch (PDOException $e) {
    echo $e->getMessage();
}
$st = $db->prepare("SELECT data FROM example WHERE id = ?");
$st->execute([1]);  // bindParamを使わずexecuteの引数でバインド
$st->bindColumn(1, $lob, PDO::PARAM_LOB);
$st->fetch(PDO::FETCH_BOUND); // boundはbindの過去形。結果セットの次行でbindColumnで設定した列をバインドした変数へ代入
header('Content-Type: image/jpeg');
echo $lob;
$dt = null;

名前付きプレースホルダの例

CREATE TABLE `sample` (
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `user` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4
$db = new PDO('mysql:host=localhost;dbname=tutorial', '<user>', '<password>');
$st = $db->prepare("select * from sample where id < :id");
$id = 5;
$st->bindParam('id', $id, PDO::PARAM_INT );
// $st->bindParam('id', 5, PDO::PARAM_INT );  Fatal error 第2引数は変数を渡す必要があります。
$st->execute();
$results = $st->fetchAll();
foreach($results as $result) {
   var_dump($result); 
}

結果セット形式(PDO::query, PDOStatement::fetchXXX)

取り出し方法 意味
PDO::FETCH_CLASS 「カラムをクラスのプロパティにマップしつつ、 指定されたクラスの新規インスタンスを返す取得方法を指定します。」PHP公式マニュアル。
PDO::FETCH_INTO 「カラムをクラスのプロパティにマップしつつ、 指定されたクラスの既存のインスタンスを更新する取得方法を指定します。」PHP公式マニュアル。
PDO::FETCH_COLUMN 「結果セットの次の行から指定された一つのカラムのみを返す取得方法を指定します。」PHP公式マニュアル。
PDO::FETCH_ASSOC カラムをキーとする連想配列として取得
PDO::FETCH_NUM インデックス配列として取得
PDO::FETCH_BOTH カラムおよび数字をキーとする配列(デフォルト)
PDO::FETCH_BOUND 「結果セットのカラムの値を PDOStatement::bindParam() または PDOStatement::bindColumn() メソッドでバインドされた PHP変数に代入し、TRUEを返すという取得方法を指定します。」php公式マニュアル。
<?php
$db = new PDO('mysql:host=localhost;dbname=tutorial;charset=utf8mb4', 'root', '50ln1317');
$st = $db->query("SELECT * FROM sample", PDO::FETCH_ASSOC);
foreach($st as $row) {
   echo $row['id'] . ': ' . $row['user'] . '<br>';
}

class Result {
    public $id, $user; // プロパティー名は列名と同一である必要があります。 
}
$st = $db->query("SELECT * FROM sample", PDO::FETCH_CLASS, 'Result');
foreach($st as $ins) {
   echo $ins->id, $ins->user, '<br>';
}

FETCH_ASSOC, FETCH_NUM, FETCH_BOTHの例

$db = new PDO('mysql:host=localhost;dbname=tutorial', 'root', '50ln1317');

echo '--- PDOStatement::fetch FETCH_BOTH ---'; 
$st = $db->prepare("select * from foo where id < ?");
$st->execute([4]);
$results = $st->fetchAll(PDO::FETCH_BOTH);
foreach($results as $row) {
   var_dump($row); 
}

echo '--- PDOStatement::fetch FETCH_ASSOC ---'; 
$st = $db->prepare("select * from foo where id < ?");
$st->execute([4]);
$results = $st->fetchAll(PDO::FETCH_ASSOC);
foreach($results as $row) {
   var_dump($row); 
}

echo '--- PDOStatement::fetch FETCH_CLASS ---'; 
$st = $db->prepare("select * from foo where id < ?");
class X {
    public $id, $user, $password;
}
$st->execute([4]);
$results = $st->fetchAll(PDO::FETCH_CLASS);
foreach($results as $obj) {
   var_dump($obj); 
}

echo '--- PDOStatement::fetch FETCH_COLUMN ---'; 
$st = $db->prepare("select * from foo where id < ?");
$st->execute([4]);
$results = $st->fetchAll(PDO::FETCH_COLUMN, 2);
foreach($results as $row) {
   var_dump($row); 
}
--- PDOStatement::fetch FETCH_BOTH ---
array
  'id' => string '1' 
  0 => string '1'
  'a' => string '10'
  1 => string '10'
  'b' => string '20'
  2 => string '20'
array
  'id' => string '2' 
  0 => string '2'
  'a' => string '3'
  1 => string '3'
  'b' => string '10'
  2 => string '10'
array 
  'id' => string '3'
  0 => string '3'
  'a' => string '8'
  1 => string '8'
  'b' => string '5'
  2 => string '5'

--- PDOStatement::fetch FETCH_ASSOC ---
array
  'id' => string '1'
  'a' => string '10'
  'b' => string '20'
array
  'id' => string '2'
  'a' => string '3'
  'b' => string '10'
array
  'id' => string '3'
  'a' => string '8'
  'b' => string '5'

--- PDOStatement::fetch FETCH_CLASS ---
object(stdClass)[3]
  public 'id' => string '1'
  public 'a' => string '10'
  public 'b' => string '20'
object(stdClass)[4]
  public 'id' => string '2'
  public 'a' => string '3'
  public 'b' => string '10'
object(stdClass)[5]
  public 'id' => string '3'
  public 'a' => string '8'
  public 'b' => string '5'

--- PDOStatement::fetch FETCH_COLUMN ---
string '20'
string '10'
string '5'

参考資料

  • http://www.php.net/manual/ja/faq.databases.php
  • http://jp2.php.net/manual/ja/mbstring.php4.req.php
  • http://jp2.php.net/manual/ja/book.pdo.php
  • http://www.php.net/manual/ja/features.persistent-connections.php

コメント

No comments yet.

コメントの投稿

改行と段落タグは自動で挿入されます。
メールアドレスは表示されません。