忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

PHP PDO クラスを使用したデータテーブル操作クラスを作成してみました


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...
 













PR

コメント

1. PHPのPDO接続の参考にさせていただきます。

はじめまして。
PDO接続を毎回宣言したりしてましたが、これならクラス化して非常に便利ですね。
PHPのPDO接続の参考にさせていただきます。
このコードを使わせていただきますがよろしいでしょうか?

2. PHPのPDO接続の参考にさせていただきます。

はじめまして。
PDO接続を毎回宣言したりしてましたが、これならクラス化して非常に便利ですね。
PHPのPDO接続の参考にさせていただきます。
このコードを使わせていただきますがよろしいでしょうか?

3. 無題

コメント有難うございます。
参考にして頂ければ、幸いです。

4. 無題

使わせていただきます。ありがとうございました。
くーへん
コメントを書く