PDO 及び PDOStatement クラスを使ったデータベースへの接続からテーブルレコード取得、及びデータレコードに対しての登録・更新・削除、さらにトランザクションについて、以下の記事で説明してきました。
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセスについて
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセス(登録、更新、削除)について
⇒PHP PDO(PHP Data Objects)クラスを使ったトランザクションについて
⇒PHP PDO(PHP Data Objects)クラスを使った「AUTO_INCREMENT」カラムの取得について
⇒PHP PDOStatement クラスの中で使うと思われるメソッド(closeCursor,errorInfo,fetchAll,rowCount)について
そこでこれらの処理を簡単に行える様にするためのクラスを作成してみました。
クラスの中で PDO クラスのインスタンスを生成し、外部から直接 PDO オブジェクトを参照することが無いようにしました。 このクラスのメソッドは以下の様になります。
| メソッド名 | 説明 |
|---|---|
| __construct | コンストラクタ(データベースへの接続) |
| getLastError | 最終発生エラー情報の取得 |
| close | データベース接続を閉じる |
| begin | トランザクション開始 |
| commit | トランザクション・コミット |
| rollback | トランザクション・ロールバック |
| prepare | [prepare]メソッドのラッパ関数 |
| lastInsertId | 最後のAUTOINCREMENTの取得 |
| execute | SQLステートメント実行(prepare, bindValue, excute を内部で順次実行) |
| getColumnData | SQLステートメント実行し1個のカラム値を取得(自身の execute メソッドを使用) |
| getSelectCount | SQLステートメント実行行数の取得(自身の getColumnData メソッドを使用) |
■クラスのスクリプト [cPDOMySQL.php]
以下にスクリプトを示します。
データベースの接続用のホスト名などのデフォルト値をこのソースの先頭に記述しています。
本来であれば、別のPHPソースまたは、ini ファイルなどで読込んで指定すべきかと思います。
<?php
// =====
// MySQLデータベース操作クラス [cPDOMySQL.php]
// =====
// デフォルトのDB指定値
define('MYSQL_HOST', 'localhost');
define('MYSQL_DBNAME', 'pdo');
define('MYSQL_CHARSET', 'UTF8');
define('MYSQL_USER', 'root');
define('MYSQL_PASSWORD','password');
class cPDOMySQL {
private $pdo; // PDOクラスインスタンス
private $host; // 接続先ホスト
private $dbname; // データベース名
private $user; // 接続ユーザ
private $password; // 接続パスワード
private $charset; // キャラクタセット名
// 最終実行SQL
private $sql;
// 最終発生エラー情報(配列データ)
// 配列[0]:SQLSTATE エラーコード (これは、ANSI SQL 標準で定義された英数 5 文字の ID)
// 配列[1]:ドライバ固有のエラーコード
// 配列[2]:ドライバ固有のエラーメッセージ
private $error;
// =====
// 最終発生エラー情報の取得
// =====
// [返り値]
// array PDO::errorInfo() または PDOStatement::errorInfo()
public function getLastError() {
return $this->error;
}
// =====
// コンストラクタ(データベースへの接続)
// =====
// [引数]
// $host string 接続先ホスト (デフォルト:MYSQL_HOST)
// $dbname string データベース名 (デフォルト:MYSQL_DBNAME)
// $charset string キャラクタセット名(デフォルト:MYSQL_CHARSET)
// $user string 接続ユーザ (デフォルト:MYSQL_USER)
// $password string 接続パスワード (デフォルト:MYSQL_PASSWORD)
public function __construct($host = MYSQL_HOST, $dbname = MYSQL_DBNAME, $charset = MYSQL_CHARSET,
$user = MYSQL_USER, $password = MYSQL_PASSWORD) {
// データベース指定値退避
$this->host = trim($host);
$this->dbname = trim($dbname);
$this->charset = trim($charset);
$this->user = trim($user);
$this->password = trim($password);
// 初期化
$this->sql = "";
$this->clearError();
// データベース接続
try {
$dsn = "mysql:host={$this->host};dbname={$this->dbname};charset={$this->charset}";
$this->pdo = new PDO($dsn, $this->user, $this->password);
} catch (PDOException $e) {
echo 'データベース接続エラー:'.$e->getMessage();
}
if ($this->pdo == false) {
die("データベースへの接続に失敗しました。");
}
}
// =====
// エラー情報クリア
// =====
protected function clearError() {
$this->error = array(0 => null, 1 => null, 2 => null);
}
// =====
// データベース接続を閉じる
// =====
public function close() {
$this->pdo = null;
}
// =====
// トランザクション開始
// =====
public function begin() {
return $this->pdo->beginTransaction();
}
// =====
// トランザクション・コミット
// =====
public function commit() {
return $this->pdo->commit();
}
// =====
// トランザクション・ロールバック
// =====
public function rollback() {
return $this->pdo->rollBack();
}
// =====
// [prepare]メソッドのラッパ関数
// =====
// [引数]
// $sql string SQLステートメント
// [返り値]
// mixed 正常終了:[PDOStatement]オブジェクト,エラー:false
public function prepare($sql) {
// エラークリア
$this->clearError();
// SQL文の準備
$pdostmt = $this->pdo->prepare($sql);
if ($pdostmt === false) {
// エラーの場合
$this->error = $pdostmt->errorInfo();
return false;
}
// [PDOStatement]オブジェクトを返す
return $pdostmt;
}
// =====
// 最後のAUTOINCREMENTの取得
// =====
// [返り値]
// mixed 正常終了:最後に挿入された行の[ID]値の文字列
// エラー :false (getLastError()でエラー情報が取得できる)
public function lastInsertId() {
// エラークリア
$this->clearError();
try {
$ret = $this->pdo->lastInsertId();
} catch (PDOException $e) {
$this->error = $e->errorInfo;
$ret = false;
}
return $ret;
}
// =====
// SQLステートメント実行
// =====
// [引数]
// $sql string SQLステートメント
// $arrBind array SQL内のプレースホルダの値の配列 array(':name' => value, ...)
// [返り値]
// mixed 正常終了:SELECT文の場合[PDOStatement]オブジェクト,
// SELECT文以外の場合 true,
// エラー :false
public function execute($sql, $arrBind = array()) {
// SQL準備
$pdostmt = $this->prepare($sql);
if ($pdostmt === false) {
return false;
}
// バインド
foreach ($arrBind as $key => $val) {
$ret = $pdostmt->bindValue($key, $val);
if ($ret === false) {
$this->error = $pdostmt->errorInfo();
return false;
}
}
// 実行
$ret = $pdostmt->execute();
if ($ret === false) {
$this->error = $pdostmt->errorInfo();
return false;
}
// SELECTステートメントの場合??
if (preg_match('/^select/i', trim($sql))) {
// [PDOStatement]オブジェクト
return $pdostmt;
}
else {
// selectステートメント以外の場合
return true;
}
}
// =====
// SQLステートメント実行し1個のカラム値を取得
// =====
// [引数]
// $sql string SQLステートメント
// $arrBind array SQL内のプレースホルダの値の配列 array(':name' => value, ...)
// $columnName string カラム名、またはカラムIndex値
// [返り値]
// mixed 正常終了:カラムの値
// エラー :false
public function getColumnData($sql, $arrBind = array(), $columnName = 0) {
// SQLステートメント実行
$pdostmt = $this->execute($sql, $arrBind);
if ($pdostmt === false) {
return false;
}
// 1行取得
$row = $pdostmt->fetch();
if ($row === false) {
// エラー
$this->error = $pdostmt->errorInfo();
$ret = false;
} else {
// カラムデータ
$ret = $row[$columnName];
}
// 接続を閉じる
$pdostmt = null;
// カラムデータを返す
return $ret;
}
// =====
// SQLステートメント実行行数の取得
// =====
// [引数]
// $sql string SQLステートメント
// $arrBind array SQL内のプレースホルダの値の配列 array(':name' => value, ...)
// [返り値]
// mixed 正常終了:件数
// エラー :false
public function getSelectCount($sql, $arrBind = array()) {
// SELECT文を SELECT count(*) でラップ
$sql = "select count(*) from ({$sql}) as tx";
// 件数を取得して返します。
return $this->getColumnData($sql, $arrBind);
}
}
?>
■クラス cPDOMySQL を利用したスクリプト例
cPDOMySQL クラスは bindValue を複数記述するのが面倒だったために、内部で繰り返し処理しています。
ただし、PDOStatement クラスのオブジェクトを取得した後の処理は、cPDOMySQL クラスの呼び出し側で 処理する必要があります。
データ取得後のデータ処理もクラス化するのであれば、このクラスを継承して、その子クラスで処理を行えばよいかと思います。 (突っ込みどころ満載かと思いますので、改変して下さい。)
取敢えず、cPDOMySQL クラスを利用したスクリプトの例を以下に記します。
<?php /* [pdoc1.php] */
include "./cPDOMySQL.php";
ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); });
// MySQLデータベース操作クラス生成(データベース接続)
$pdo = new cPDOMySQL();
// データ取得SQL(名前付きパラメータ)
$sqlList = "select * from `tm_shohin` where id >= :id1 and id <= :id2 order by id";
// SELECTクエリのパラメータに実際の値設定と実行
$pdostmt = $pdo->execute($sqlList, array(":id1" => "1", ":id2" => "3"));
// PDOStatementクラスの fetch メソッドで1行のデータ取得
while ($result = $pdostmt->fetch()) {
// データが取得できた場合(データ表示)
echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n";
}
echo "end...\n";
$ret = $pdo->getSelectCount($sqlList, array(":id1" => "1", ":id2" => "3"));
echo "getSelectCount...[$ret]\n";
$ret = $pdo->getColumnData("select now()");
echo "system time...[$ret]\n";
// トランザクション開始
$ret = $pdo->begin();
if ($ret == true) {
// トランザクション開始OK
try {
// レコード登録(INSERT)SQL
$sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)";
// SQL文の実行([id:3]のデータ)
if ($ret == true) {
$arrPara = array(":id" => 3, ":name" => 'パソコン003', ":price" => 303000);
$ret = $pdo->execute($sql, $arrPara);
}
// SQL文の実行([id:4]のデータ)
if ($ret == true) {
$arrPara = array(":id" => 4, ":name" => 'プリンタ001', ":price" => 50000);
$ret = $pdo->execute($sql, $arrPara);
}
} catch (Exception $e) {
// 何かスクリプト上のエラーが在った!!
$ret = false;
}
// トランザクション終了処理
if ($ret == true) {
// コミット
$pdo->commit();
} else {
// ロールバック
$pdo->rollback();
}
} else {
// トランザクション開始NG
}
// 再度、SELECTクエリのパラメータに実際の値設定と実行
$pdostmt = $pdo->execute($sqlList, array(":id1" => "1", ":id2" => "4"));
// PDOStatementクラスの fetch メソッドで1行のデータ取得
while ($result = $pdostmt->fetch()) {
// データが取得できた場合(データ表示)
echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n";
}
echo "end...\n";
// 接続を閉じる
$pdo->close();
?>
これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdoc1.php id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 end... getSelectCount...[2] system time...[2020-12-07 18:07:58] id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 end...
コメント
1. PHPのPDO接続の参考にさせていただきます。
PDO接続を毎回宣言したりしてましたが、これならクラス化して非常に便利ですね。
PHPのPDO接続の参考にさせていただきます。
このコードを使わせていただきますがよろしいでしょうか?
2. PHPのPDO接続の参考にさせていただきます。
PDO接続を毎回宣言したりしてましたが、これならクラス化して非常に便利ですね。
PHPのPDO接続の参考にさせていただきます。
このコードを使わせていただきますがよろしいでしょうか?
3. 無題
参考にして頂ければ、幸いです。
4. 無題
くーへん