iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
0
Modern Web

寫給朋友的 PHP 從 0 到 100 實戰教程系列 第 16

Day 16. PHP教程: 將 MySQLi 升級為 PDO (PHP Data Object)

Why
為什麼要升級成 PDO 呢? 這個 PHP Data Object 到底有多厲害呢?

  • PDO 可以隨時切換成其他資料庫
  • 可以將查詢到的資料直接轉成對應的物件
  • 增強安全性,不在需要 mysqli_real_escape_string 的處理

How
就來改寫連接資料庫用的物件吧
DatabaseAccessObject.php

<?php
class DatabaseAccessObject {
    private $mysql_address = "";
    private $mysql_username = "";
    private $mysql_password = "";
    private $mysql_database = "";
    private $db;
    private $last_sql = "";
    private $last_id = 0;
    private $last_num_rows = 0;
    private $error_message = "";

    /**
     * 這段是『建構式』會在物件被 new 時自動執行,裡面主要是建立跟資料庫的連接,並設定語系是萬國語言以支援中文
     */
    public function __construct($mysql_address, $mysql_username, $mysql_password, $mysql_database) {
        $this->mysql_address  = $mysql_address;
        $this->mysql_username = $mysql_username;
        $this->mysql_password = $mysql_password;
        $this->mysql_database = $mysql_database;

        try {
            $db = new PDO("mysql:host=".$this->mysql_address.";charset=utf8mb4;dbname=".$this->mysql_database, $this->mysql_username, $this->mysql_password);
            //$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);//Suggested to uncomment on production websites
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);//Suggested to comment on production websites
            $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

            $this->db = $db;
        
        } catch(PDOException $e) {
            //show error
            echo '<p class="bg-danger">'.$e->getMessage().'</p>';
            exit;
        } 
    }

    /**
     * 這段是『解構式』會在物件被 unset 時自動執行,裡面那行指令是切斷跟資料庫的連接
     */
    public function __destruct() {
        $this->db = null;
    }

    /**
     * 這段用來執行 MYSQL 資料庫的語法,可以靈活使用
     */
    public function execute($sql = null, $data_array) {
        try {
            $stmt = $this->db->prepare($sql);
            $stmt->execute($data_array);
            return $stmt->fetchAll(); 
		} catch(PDOException $e) {
		    $this->error_message = '<p class="bg-danger">'.$e->getMessage().'</p>';
		}
    }

    /**
     * 這段用來讀取資料庫中的資料,回傳的是陣列資料
     */
    public function query($table, $condition, $order_by, $fields, $limit, $data_array){
        if(!isset($data_array) OR count($data_array) == 0)return false;
        if(empty($table))return false;
        if(is_numeric($limit))$limit = "LIMIT ".$limit;
        if(empty($condition))$condition = 1;
        if(empty($order_by))$order_by = 1;
        if(empty($fields))$fields = "*";
        $this->last_sql = "SELECT {$fields} FROM {$table} WHERE {$condition} ORDER BY {$order_by} {$limit}";
        try {
			$stmt = $this->db->prepare($this->last_sql);
			$stmt->execute($data_array);
            return $stmt->fetchAll();
		} catch(PDOException $e) {
		    $this->error_message = '<p class="bg-danger">'.$e->getMessage().'</p>';
        }
    }

    /**
     * 這段可以新增資料庫中的資料,並把最後一筆的 ID 存到變數中,可以用 getLastId() 取出
     */
    public function insert($table = null, $data_array = array()) {
        if($table===null)return false;
        if(count($data_array) == 0) return false;

        $tmp_col = array();
        $tmp_dat = array();

        foreach ($data_array as $key => $value) {
            $tmp_col[] = $key;
            $tmp_dat[] = ":$key";
            $prepare_array[":".$key] = $value;
        }
        $columns = join(",", $tmp_col);
        $data = join(",", $tmp_dat);

        $this->last_sql = "INSERT INTO " . $table . "(" . $columns . ")VALUES(" . $data . ")";
        $stmt = $this->db->prepare($this->last_sql);
        $stmt->execute($prepare_array);
        $this->last_id = $this->db->lastInsertId();
    }

    /**
     * 這段可以更新資料庫中的資料
     */
    public function update($table = null, $data_array = null, $key_column = null, $id = null) {
        if($table == null)return false;
        if($id == null) return false;
        if($key_column == null) return false;
        if(count($data_array) == 0) return false;

        $setting_list = "";
        for ($xx = 0; $xx < count($data_array); $xx++) {
            list($key, $value) = each($data_array);
            $setting_list .= $key . "=" . ':'.$key;
            if ($xx != count($data_array) - 1){
                $setting_list .= ",";
            }
        }
        $data_array[$key_column] = $id;
        $this->last_sql = "UPDATE " . $table . " SET " . $setting_list . " WHERE " . $key_column . " = " . ":".$key_column;
        $stmt = $this->db->prepare($this->last_sql);                       
        $stmt->execute($data_array);
    }
    /**
     * 這段可以刪除資料庫中的資料
     */
    public function delete($table = null, $key_column = null, $id = null) {
        if ($table===null) return false;
        if($id===null) return false;
        if($key_column===null) return false;

        $this->last_sql = "DELETE FROM $table WHERE " . $key_column . " = " . ':'.$key_column;
        $stmt = $this->db->prepare($this->last_sql);
        $stmt->execute(array( ':'.$key_column => $id));
    }

    /**
     * @return string
     * 這段會把最後執行的語法回傳給你
     */
    public function getLastSql() {
        return $this->last_sql;
    }

    /**
     * @param string $last_sql
     * 這段是把執行的語法存到變數裡,設定成 private 只有內部可以使用,外部無法呼叫
     */
    private function setLastSql($last_sql) {
        $this->last_sql = $last_sql;
    }

    /**
     * @return int
     * 主要功能是把新增的 ID 傳到物件外面
     */
    public function getLastId() {
        return $this->last_id;
    }

    /**
     * @param int $last_id
     * 把這個 $last_id 存到物件內的變數
     */
    private function setLastId($last_id) {
        $this->last_id = $last_id;
    }

    /**
     * @return int
     */
    public function getLastNumRows() {
        return $this->last_num_rows;
    }

    /**
     * @param int $last_num_rows
     */
    private function setLastNumRows($last_num_rows) {
        $this->last_num_rows = $last_num_rows;
    }

    /**
     * @return string
     * 取出物件內的錯誤訊息
     */
    public function getErrorMessage()
    {
        return $this->error_message;
    }

    /**
     * @param string $error_message
     * 記下錯誤訊息到物件變數內
     */
    private function setErrorMessage($error_message)
    {
        $this->error_message = $error_message;
    }
}

上一篇
Day 15. PHP教學: 用 phpmailer + gmail smtp 實作寄信功能
下一篇
Day 17. PHP教學: 實作註冊流程
系列文
寫給朋友的 PHP 從 0 到 100 實戰教程30

尚未有邦友留言

立即登入留言