(3)php框架開發---數據庫模型開發

今天有空再寫一篇php的數據庫模型類開發,這次的數據庫類採用的是pdo來實現的,因爲pdo有較好的適用性,所以使用pdo比mysql,mysqli都要好用。

首先就是要確定基本的思路,首先要有一個模型類model.php,然後這個模型類有一個保護成員變量,這個變量用來保存數據庫的對象,所以這裏要使用一個數據庫管理類db.php來規範管理所有的數據庫對象,這些對象都保存在一個數據中,然後就可以非常的容易切換,之後就是各個數據庫驅動mysql,mysqli等,這些驅動都要繼承最基本的驅動類dirver.php這個驅動基本類。

基本的結構如下圖:


數據庫驅動文件類,這個類封裝了基本的sql方法和變量,因爲大多數的sql都使用到這些方法,所以做一個封裝,然後讓其它類繼承。

driver類:

<?php
/**
 * Created by PhpStorm.
 * User: DMF
 * Date: 2017/9/23
 * Time: 15:59
 */

namespace Dphp\core\database;


class driver
{
    //數據庫配置
    protected $config = array(
        'type'              =>  'mysql',     // 數據庫類型
        'hostname'          =>  '127.0.0.1', // 服務器地址
        'database'          =>  'test',          // 數據庫名
        'username'          =>  'root',      // 用戶名
        'password'          =>  'root',          // 密碼
        'hostport'          =>  '8081',        // 端口
        'dsn'               =>  'mysql:host=localhost;dbname=test', //pdo連接信息
    );

    //數據庫pdo連接id 支持多個連接
    protected $linkId = array();
    //當前pdo連接id
    protected $_linkId = null;
    //pdo操作實例
    protected $pdoStatement = null;
    // 事務指令數
    protected $transTimes = 0;
    //當前sql指令
    protected $querySql = '';
    // 錯誤信息
    protected $error      = '';
    //pdo連接參數
    protected $options = array(

    );
    protected $bind = array(); // 參數綁定

    //連接數據庫函數
    public function connect($config=array()){
        if(empty($config)){
            $config = $this->config;
        }
        try{
            $this->_linkId = new \PDO($config['dsn'],$config['username'],$config['password']);
            echo "連接成功<br/>";
        }catch (\PDOException $e) {
            echo $e->errorInfo(),$e->getMessage();
            die ("Error!: " . $e->getMessage() . "<br/>");
        }

        return $this->_linkId;
    }

    //釋放查詢結果
    public function free(){
        $this->pdoStatement = null;
    }



    //執行查詢,並返回結果集
    public function query($sql,$fetchSql=false){

        echo '<br/>'.$sql.'<br/>';
        $this->initConnect();
        //判斷是否初始化失敗
        if(!$this->_linkId)return fasle;
        try{
            //pdo執行sql語句準備
            $this->pdoStatement = $this->_linkId->prepare($sql);

        }catch (\PDOException $e) {
            echo $e->getMessage();
            return false;
        }
        if($this->pdoStatement === false){
            return false;
        }

        //數據綁定
        foreach($this->bind as $k=>$v){
            $this->pdoStatement->bindParam($k,$v);
        }

        //執行完成清空綁定數據數組
        $this->bind = array();

        //執行sql語句
        $this->pdoStatement->execute();
        //返回sql執行結果集
        return $this->pdoStatement->fetchAll(\PDO::FETCH_ASSOC);

    }

    //執行查詢,並返回結果集
    public function execute($sql,$fetchSql=false){

        echo '<br/>'.$sql.'<br/>';
        $this->initConnect();
        //判斷是否初始化失敗
        if(!$this->_linkId)return fasle;
        try{
            //pdo執行sql語句準備
            $this->pdoStatement = $this->_linkId->prepare($sql);

        }catch (\PDOException $e) {
            echo $e->getMessage();
            return false;
        }

        if($this->pdoStatement === false){
            return false;
        }

        //數據綁定
        foreach($this->bind as $k=>$v){
            $this->pdoStatement->bindParam($k,$v);
        }

        //執行完成清空綁定數據數組
        $this->bind = array();

        //執行sql語句
        return $this->pdoStatement->execute();

        //var_dump($this->pdoStatement->errorInfo());

    }


    //啓動事務
    public function startTransaction(){
        $this->connect();
        if(!$this->_linkId)return false;
        if($this->transTimes == 0){
            $this->_linkId->beginTransaction();
        }
        $this->transTimes++;
    }

    //提交數據,要非自動提交
    public function commit(){
        if($this->transTimes>0){
            $result = $this->_linkId->commit();
            $this->transTimes = 0;
            if(!$result){
                $this->error();
                return false;
            }
        }
        return true;
    }

    //回滾數據
    public function rollback(){
        if($this->transTimes>0){
            $result = $this->_linkId->rollback();
            $this->transTimes = 0;
            if(!$result){
                $this->error();
                return false;
            }
        }
        return true;
    }

    //初始化連接
    protected function initConnect(){
        //判斷是否存在連接對象
       if(!$this->_linkId)$this->_linkId = $this->connect();
    }

    //關閉數據庫
    public function close(){
        $this->_linkId = null;
    }

    //數據庫錯誤信息
    public function error(){
        if($this->pdoStatement){
            $error = $this->pdoStatement->errorInfo();
            $this->error = $error[1].':'.$error[2];
        }else{
            $this->error = '';
        }
        return $this->error;
    }

    //析構函數
    public function __destruct()
    {
        // TODO: Implement __destruct() method.
        if($this->pdoStatement){
            $this->free();
        }
        //關閉數據庫連接
        $this->close();
    }

    /*
     * 數據綁定
     * $name:名
     * $value:值
     */
    public function bindParam($name,$value){
        $this->bind[':'.$name] = $value;
    }


    /*
     * 插入數據
     * $table:數據表
     * $data:插入數據
     */
    public function insert($table='',$data=array()){
        if(empty($data)){
            die('數據不能爲空!');
        }

        //字段名處理
        foreach($data as $k=>$v){
            $fields[] = $k;
            $values[] = $v;
            $this->bindParam($k,$v);
        }

        //insert的sql語句處理
        $sql = 'INSERT INTO '.$table.' ( '.implode(',',$fields)
            .') VALUES (';
        foreach($fields as $k=>$v){
            $sql.=':'.$v.',';
        }
        $sql = rtrim($sql,',');
        $sql .= ')';
        echo '<br/>'.$sql.'<br/>';

        return $this->execute($sql);
    }

    /*
     * 刪除數據
     * $table:表名
     * $data:插入數據
     */
    public function delete($table='',$id=''){
        $sql = 'DELETE FROM '.$table.' WHERE id='.$id;
        echo $sql.'<br/>';
        return $this->execute($sql);
    }

    /*
     * 修改數據
     * $table:表名
     * $data:插入數據
     */
    public function update($table='',$data=array()){
        if(empty($data)){
            die('數據不能爲空!');
        }

        $sql = 'UPDATE '.$table.' SET ';
        //字段名處理
        foreach($data as $k=>$v) {

            $sql = $sql.$k.'=:'.$k.',';

            $this->bindParam($k,$v);
        }
        $sql = rtrim($sql,',');
        $sql = $sql.' WHERE id='.$data['id'];
        #echo $sql.'<br/>';
       return $this->execute($sql);
    }

    /*
     * 查詢數據
     * $table:表名
     * $data:插入數據
     */
    public function select($table='',$option=array()){

        $sql = 'SELECT * FROM '.$table.' WHERE ';
        foreach($option as $k=>$v){
            $sql .= $k.'=:'.$k .' AND ';
        }
        $sql = rtrim($sql,' AND ');
        echo $sql.'<br/>';
        foreach($option as $k=>$v) {

            $this->bindParam($k,$v);
        }

        return $this->query($sql);
    }

}

繼承驅動類的mysqli類,這裏可以寫一些mysqli獨有的方法,方便拓展開來

mysqli類:

<?php
/**
 * Created by PhpStorm.
 * User: DMF
 * Date: 2017/9/23
 * Time: 17:12
 */

namespace Dphp\core\database\sqlDriver;


class mysqli extends \Dphp\core\database\driver
{

}


db類其實就是用來全局靜態的方法獲取數據庫實例對象,這樣做的好處是,在使用同一個數據庫對象的時候,我只要new一次就可以了。這裏防止重複new相同的數據庫,所以性能上是會有一定的提升。

db類:

<?php
/**
 * Created by PhpStorm.
 * User: DMF
 * Date: 2017/9/23
 * Time: 15:55
 */

namespace Dphp\core;


class db
{
    static private $instance = array();     //數據庫連接實例
    static private $_instance = null;       //當前數據庫實例
    //獲取數據庫實例
    static public function getInstance($config=array()){

        $md5 = md5(serialize($config));
        //判斷是否存在數據庫實例對象
        if(!isset(self::$instance[$md5])){
            $class = 'Dphp\\core\\database\\sqlDriver\\mysqli';
            self::$instance[$md5] = new $class();
            echo 'new了一個數據庫對象<br/>';
        }
        else {
            echo '緩存一個數據庫對象<br/>';
        }
        return self::$instance[$md5];
    }



}

直接提供操作數據庫的接口方法。

model類:

<?php
/**
 * Created by PhpStorm.
 * User: DMF
 * Date: 2017/9/25
 * Time: 13:12
 */

namespace Dphp\core;


class model
{
    //數據庫對象
    protected $db;


    //初始化數據庫對象
    public function __construct($name='')
    {
        $this->db();
    }

    //數據庫對象實例化
    public function db(){
        if($this->db)return $this->db;
        //獲取數據庫對象
        $this->db = \Dphp\core\db::getInstance();
        return $this->db;
    }

    /*
     * 數據添加
     * $table:表名
     * $data:添加的數據
     */
    public function add($table='',$data=array()){

        if(empty($table)||empty($data)){
            die('數據表爲空或數據爲空');
        }

        return $this->db->insert($table,$data);
        //var_dump($data2);
    }

    /*
     * 數據更新
     * $table:表名
     * $data:添加的數據
     */
    public function update($table='',$data=array()){

        if(empty($table)||empty($data)){
            die('數據表爲空或數據爲空');
        }

        return $this->db->update($table,$data);
        //var_dump($data2);
    }

    /*
     * 數據刪除
     * $table:表名
     * $data:添加的數據
     */
    public function delete($table='',$id=null){

        if(empty($table)||empty($id)){
            die('數據表爲空或數據爲空');
        }

        return $this->db->delete($table,$id);
        //var_dump($data2);
    }

    /*
    * 數據查找
    * $table:表名
    * $data:添加的數據
    */
    public function select($table='',$option=array()){

        if(empty($table)||empty($option)){
            die('數據表爲空或數據爲空');
        }

        return $this->db->select($table,$option);
        //var_dump($data2);
    }
}



2017.10.31

在上面的數據庫寫法上,其實存在着一個bug和不方便的地方。


這裏面我的數據庫driver裏面沒寫人性化,因爲query的時候沒用給你綁定數據的參數傳入。所以更改後應該是這樣子的。

<?php
/**
 * Created by PhpStorm.
 * User: DMF
 * Date: 2017/9/23
 * Time: 15:59
 */

namespace core\database;

class driver
{
    //數據庫配置
    protected $config = array(
        'type'              =>  'mysql',     // 數據庫類型
        'hostname'          =>  '127.0.0.1', // 服務器地址
        'database'          =>  '123',          // 數據庫名
        'username'          =>  'root',      // 用戶名
        'password'          =>  'root',          // 密碼
        'hostport'          =>  '3306',        // 端口
        'dsn'               =>  'mysql:host=localhost;dbname=automobileRepairStation', //pdo連接信息
    );

    //數據庫pdo連接id 支持多個連接
    protected $linkId = array();
    //當前pdo連接id
    protected $_linkId = null;
    //pdo操作實例
    protected $pdoStatement = null;
    // 事務指令數
    protected $transTimes = 0;
    //當前sql指令
    protected $querySql = '';
    // 錯誤信息
    protected $error      = '';
    //pdo連接參數
    protected $options = array(

    );
    protected $bind = array(); // 參數綁定

    //連接數據庫函數
    public function connect($config=array()){
        if(empty($config)){
            $config = $this->config;
        }
        try{
            $this->_linkId = new \PDO($config['dsn'],$config['username'],$config['password']);
            #echo "連接成功<br/>";
        }catch (\PDOException $e) {
            #echo $e->errorInfo(),$e->getMessage();
            die ("Error!: " . $e->getMessage() . "<br/>");
        }

        return $this->_linkId;
    }

    //釋放查詢結果
    public function free(){
        $this->pdoStatement = null;
    }


    //啓動事務
    public function startTransaction(){
        $this->connect();
        if(!$this->_linkId)return false;
        if($this->transTimes == 0){
            $this->_linkId->beginTransaction();
        }
        $this->transTimes++;
    }

    //提交數據,要非自動提交
    public function commit(){
        if($this->transTimes>0){
            $result = $this->_linkId->commit();
            $this->transTimes = 0;
            if(!$result){
                $this->error();
                return false;
            }
        }
        return true;
    }

    //回滾數據
    public function rollback(){
        if($this->transTimes>0){
            $result = $this->_linkId->rollback();
            $this->transTimes = 0;
            if(!$result){
                $this->error();
                return false;
            }
        }
        return true;
    }

    //初始化連接
    protected function initConnect(){
        //判斷是否存在連接對象
       if(!$this->_linkId)$this->_linkId = $this->connect();
    }

    //關閉數據庫
    public function close(){
        $this->_linkId = null;
    }

    //數據庫錯誤信息
    public function error(){
        if($this->pdoStatement){
            $error = $this->pdoStatement->errorInfo();
            $this->error = $error[1].':'.$error[2];
        }else{
            $this->error = '';
        }
        return $this->error;
    }

    //析構函數
    public function __destruct()
    {
        // TODO: Implement __destruct() method.
        if($this->pdoStatement){
            $this->free();
        }
        //關閉數據庫連接
        $this->close();
    }



    //執行查詢,並返回結果集
    public function query($sql,$fetchSql=false){

        #echo '<br/>'.$sql.'<br/>';
        $this->initConnect();
        //判斷是否初始化失敗
        if(!$this->_linkId)return fasle;
        try{
            //pdo執行sql語句準備
            $this->pdoStatement = $this->_linkId->prepare($sql);

        }catch (\PDOException $e) {
            echo $e->getMessage();
            return false;
        }

        return $this;
    }

    /*
     * 數據綁定
     * $name:名
     * $value:值
     */
    public function bindParam($name,$value){
        $this->bind[':'.$name] = $value;
    }

    /*
     * 數據綁定
     * $params:鍵值對參數數組
     */
    public function bind($params=null){

        if(is_array($params)){
            foreach($params as $k=>$v){

                $this->bindParam($k,$v);
            }
        }

        return $this;
    }

    /*
 * 執行並返回數據
 */
    public function fetch(){

        if(!empty($this->bind)){
            //數據綁定
            foreach($this->bind as $k=>&$v){
                $this->pdoStatement->bindParam($k,$v);
            }

        }

        //執行完成清空綁定數據數組
        $this->bind = array();
        //執行sql語句
        $this->pdoStatement->execute();

        //返回sql執行結果集
        return $this->pdoStatement->fetch(\PDO::FETCH_ASSOC);
    }

    /*
     * 執行並返回數據集
     */
    public function fetchAll(){

        if(!empty($this->bind)){
            //數據綁定
            foreach($this->bind as $k=>&$v){
                $this->pdoStatement->bindParam($k,$v);
            }

        }

        //執行完成清空綁定數據數組
        $this->bind = array();
        //執行sql語句
        $this->pdoStatement->execute();

        //返回sql執行結果集
        return $this->pdoStatement->fetchAll(\PDO::FETCH_ASSOC);
    }

    //執行查詢
    public function execute(){

            //數據綁定
            foreach($this->bind as $k=>&$v){

                $this->pdoStatement->bindParam($k,$v);
            }


        //執行sql語句
        $flag =  $this->pdoStatement->execute();

        //執行完成清空綁定數據數組
        $this->bind = array();

        if($flag){
            return true;
        }
        return false;

    }

    /*
     * 插入數據
     * $table:數據表
     * $data:插入數據
     */
    public function insert($table='',$data=array()){
        if(empty($data)){
            die('數據不能爲空!');
        }

        //字段名處理
        foreach($data as $k=>$v){
            $fields[] = $k;
            $values[] = $v;
            $this->bindParam($k,$v);
        }

        //insert的sql語句處理
        $sql = 'INSERT INTO '.$table.' ( '.implode(',',$fields)
            .') VALUES (';
        foreach($fields as $k=>$v){
            $sql.=':'.$v.',';
        }
        $sql = rtrim($sql,',');
        $sql .= ')';
        echo '<br/>'.$sql.'<br/>';

        return $this->execute($sql);
    }

    /*
     * 刪除數據
     * $table:表名
     * $data:插入數據
     */
    public function delete($table='',$id=''){
        $sql = 'DELETE FROM '.$table.' WHERE id='.$id;
        echo $sql.'<br/>';
        return $this->execute($sql);
    }

    /*
     * 修改數據
     * $table:表名
     * $data:插入數據
     */
    public function update($table='',$data=array()){
        if(empty($data)){
            die('數據不能爲空!');
        }

        $sql = 'UPDATE '.$table.' SET ';
        //字段名處理
        foreach($data as $k=>$v) {

            $sql = $sql.$k.'=:'.$k.',';

            $this->bindParam($k,$v);
        }
        $sql = rtrim($sql,',');
        $sql = $sql.' WHERE id='.$data['id'];
        #echo $sql.'<br/>';
       return $this->execute($sql);
    }

    /*
     * 查詢數據
     * $table:表名
     * $data:插入數據
     */
    public function select($table='',$option=array()){

        $sql = 'SELECT * FROM '.$table.' WHERE ';
        foreach($option as $k=>$v){
            $sql .= $k.'=:'.$k .' AND ';
        }
        $sql = rtrim($sql,' AND ');
        echo $sql.'<br/>';
        foreach($option as $k=>$v) {

            $this->bindParam($k,$v);
        }

        return $this->query($sql);
    }

}


仔細觀察的話,我是將裏面的方法細化了,加多了bind方法,fetch方法,fetchAll方法,execute方法。這樣子就能夠將query方法獲取到pdoStatement,後再綁定數據到全局變量bind裏面,然後再執行返回什麼方法的結果集。

在使用bind的方法中,肯定會使用到bindParam的方法,這裏面存在一個坑點,那就是bindParam(鍵,&值)的形式來進行綁定值的,所以當你使用foreach($values as $k=>$v)的時候,就會出現一直都是引用$v這個變量的值,所以一直都是最後面的獲取到的值。所以這裏要採用foreach($values as $k=>&$v)或是binValue這個函數。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章