iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 6
12
Modern Web

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

Day 6. PHP教學: 用物件的方式連接MYSQL 資料庫 (含範例)

  • 分享至 

  • xImage
  •  

Why
為什麼要用到資料庫呢?
因為如果我們把攻略資料都寫死,寫成文字檔案,
像是大篇幅文章一樣的話
那要新增、修改文章的人是不是都要懂 HTML 跟 PHP 語法
如果可以有一個地方可以儲存資料,我們透過管理後台修改資料後
大家瀏覽的網站資料就會自動更新,全程不用碰到程式碼。
那程式設計師就可以去做更有趣的開發工作了。

How
我們需要安裝一個資料庫,用途是來儲存資料。
市面上有非常多種資料庫可以使用
今天要講的是 MYSQL 也是最常跟 PHP 配合的夥伴
安裝方式可以上網 Google 依據你的作業系統,
資料已經多到爆掉,我這邊就不提了。
我要用昨天的 class 把連接的方式物件化,
實作出簡單好用的物件,來應用到後續的實作上!

What
直接來看 class 類別設計書:

<?php
class DatabaseAccessObject {
    private $mysql_address = "";
    private $mysql_username = "";
    private $mysql_password = "";
    private $mysql_database = "";
    private $link;
    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;

        $this->link = ($GLOBALS["___mysqli_ston"] = mysqli_connect($this->mysql_address, $this->mysql_username, $this->mysql_password));

        if (mysqli_connect_errno())
        {
            $this->error_message = "Failed to connect to MySQL: " . mysqli_connect_error();
            echo $this->error_message;
            return false;
        }
        mysqli_query($GLOBALS["___mysqli_ston"], "SET NAMES utf8");
        mysqli_query($this->link, "SET NAMES utf8");
        mysqli_query($this->link, "SET CHARACTER_SET_database= utf8");
        mysqli_query($this->link, "SET CHARACTER_SET_CLIENT= utf8");
        mysqli_query($this->link, "SET CHARACTER_SET_RESULTS= utf8");

        if(!(bool)mysqli_query($this->link, "USE ".$this->mysql_database))$this->error_message = 'Database '.$this->mysql_database.' does not exist!';
    }

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

    /**
     * 這段用來執行 MYSQL 資料庫的語法,可以靈活使用
     */
    public function execute($sql = null) {
        if ($sql===null) return false;
        $this->last_sql = str_ireplace("DROP","",$sql);
        $result_set = array();

        $result = mysqli_query($this->link, $this->last_sql);

        if (((is_object($this->link)) ? mysqli_error($this->link) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false))) {
            $this->error_message = "MySQL ERROR: " . ((is_object($this->link)) ? mysqli_error($this->link) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false));
        } else {
            $this->last_num_rows = @mysqli_num_rows($result);
            for ($xx = 0; $xx < @mysqli_num_rows($result); $xx++) {
                $result_set[$xx] = mysqli_fetch_assoc($result);
            }
            if(isset($result_set)) {
                return $result_set;
            }else{
                $this->error_message = "result: zero";
            }
        }
    }

    /**
     * 這段用來讀取資料庫中的資料,回傳的是陣列資料
     */
    public function query($table = null, $condition = "1", $order_by = "1", $fields = "*", $limit = ""){
        $sql = "SELECT {$fields} FROM {$table} WHERE {$condition} ORDER BY {$order_by} {$limit}";
        return $this->execute($sql);
    }

    /**
     * 這段可以新增資料庫中的資料,並把最後一筆的 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) {
            $value = mysqli_real_escape_string($this->link, $value);
            $tmp_col[] = $key;
            $tmp_dat[] = "'$value'";
        }
        $columns = join(",", $tmp_col);
        $data = join(",", $tmp_dat);

        $this->last_sql = "INSERT INTO " . $table . "(" . $columns . ")VALUES(" . $data . ")";

        mysqli_query($this->link, $this->last_sql);

        if (((is_object($this->link)) ? mysqli_error($this->link) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false))) {
            echo "MySQL Update Error: " . ((is_object($this->link)) ? mysqli_error($this->link) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false));
        } else {
            $this->last_id = mysqli_insert_id($this->link);
            return $this->last_id;
        }
    }

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

        $id = mysqli_real_escape_string($this->link, $id);

        $setting_list = "";
        for ($xx = 0; $xx < count($data_array); $xx++) {
            list($key, $value) = each($data_array);
            $value = mysqli_real_escape_string($this->link, $value);
            $setting_list .= $key . "=" . "\"" . $value . "\"";
            if ($xx != count($data_array) - 1)
                $setting_list .= ",";
        }
        $this->last_sql = "UPDATE " . $table . " SET " . $setting_list . " WHERE " . $key_column . " = " . "\"" . $id . "\"";
        $result = mysqli_query($this->link, $this->last_sql);

        if (((is_object($this->link)) ? mysqli_error($this->link) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false))) {
            echo "MySQL Update Error: " . ((is_object($this->link)) ? mysqli_error($this->link) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false));
        } else {
            return $result;
        }
    }
    /**
     * 這段可以刪除資料庫中的資料
     */
    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;

        return $this->execute("DELETE FROM $table WHERE " . $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;
    }
}

我們可以這樣使用這個物件 Object

$mysql_address = "localhost"; // 通常是連接同一台機器,如果是遠端就設 IP
$mysql_username = "root";     // 設定連接資料庫用戶帳號
$mysql_password = "password"; // 設定連接資料庫用戶的密碼
$mysql_database = "game";     // 設成你在 mysql 創的資料庫
$DAO = new DatabaseAccessObject($mysql_address, $mysql_username, $mysql_password, $mysql_database);
// 要新增資料就:
$table = "hero"; // 設定你想新增資料的資料表
$data_array['hero_name'] = "凡恩";
$data_array['hero_hp'] = 100;
$data_array['hero_mp'] = 80;
$DAO->insert($table, $data_array);
$hero_id = $DAO->getLastId; // 可以拿到他自動建立的 id
// 這樣就完成新增動作了

// 想要查詢的話
$table = "hero"; // 設定你想查詢資料的資料表
$condition = "hero_name = '凡恩'";
$hero = $DAO->query($table, $condition, $order_by = "1", $fields = "*", $limit = "");
// 這樣寫等同於下面直接呼叫的語法:
$hero = $DAO->execute("SELECT * FROM hero WHERE hero_name = '凡恩'");
print_r($hero); // 可以印出來看看

// 那想修改資料呢?
$table = "hero";
$data_array['hero_name'] = "凡恩ATM"; // 想改他的名字
$key_column = "hero_id"; //
$id = $hero_id; // 根據我們剛剛上面拿到的 hero ID
$DAO->update($table, $data_array, $key_column, $id);
echo $DAO->getLastSql; // 想知道會轉換成什麼語法 可以印出來看看

// 最後的刪除也不難,告訴他條件就可以了
$table = "hero";
$key_column = "hero_id";
$id = 1; // 我們假設要刪除 hero_id = 1 的英雄
DAO->delete($table, $key_column, $id); 
// 一行搞定

補上 hero 這張表的 SQL 語法 貼到 phpmyadmin 裡面先選好 database 後就可以新增囉

--
-- Table structure for table `hero`
--

CREATE TABLE IF NOT EXISTS `hero` (
`hero_id` int(11) NOT NULL,
  `hero_name` varchar(30) NOT NULL,
  `hero_hp` int(11) NOT NULL,
  `hero_mp` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `hero`
--
ALTER TABLE `hero`
 ADD PRIMARY KEY (`hero_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `hero`
--
ALTER TABLE `hero`
MODIFY `hero_id` int(11) NOT NULL AUTO_INCREMENT;

今天提供一個連接資料庫的 PHP 物件,有沒有感覺在使用上精簡很多
這是『封裝』的好處,另外我省略了一些資料庫的概念說明
這需要一些前置的課程,但是我覺得還是專注在 PHP 語法上做說明
如果有需要可以留言告訴我,我找地方另外開個主題來說明。

喜歡我的文章可以按個讚,也歡迎訂閱下一期教學文章,分享給想學程式的好朋友


上一篇
Day 5. PHP教學: 開始架設自己的遊戲攻略網站 (class 物件篇)
下一篇
Day 7. PHP教學: 架設 PHP 網站開發環境
系列文
寫給朋友的 PHP 從 0 到 100 實戰教程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
rules
iT邦新手 5 級 ‧ 2018-01-16 15:34:09

請問一下這篇是不是沒有創建"hero"資料表的語法

看更多先前的回應...收起先前的回應...
falconwei iT邦新手 5 級 ‧ 2018-01-16 22:57:36 檢舉

沒問題!補上了

請問如果我有需要,想要知道更多,敢請可以留言告訴您嗎?謝謝!可以勞煩您找地方另外開個主題來說明嗎?感恩!

請問如果我有需要,想要知道更多,敢請可以留言告訴您嗎?謝謝!可以勞煩您找地方另外開個主題來說明嗎?感恩!

falconwei iT邦新手 5 級 ‧ 2018-04-04 23:00:37 檢舉

可以直接私我訊息哦

0
j2ian
iT邦新手 5 級 ‧ 2018-08-25 01:54:36

$hero_id = $DAO->getLastId;
出現Undefined property
請問是否應為$hero_id = $DAO->getLastId();

1
no027843
iT邦新手 5 級 ‧ 2020-06-16 16:27:31

到這邊就有點跳太多ㄌ...完全跟不上R

微笑 iT邦研究生 5 級 ‧ 2020-12-28 15:16:15 檢舉

要稍微補充一下SQL的基本知識

筆者沒有提到環境架設的部分,如果自己去建一次環境的話,再來看多少會比較好看懂

0
Patrick_Star
iT邦新手 5 級 ‧ 2021-08-31 23:48:48

看到SQL 就.....銜接不上了
版大 有沒有看了甚麼東西 能比較理解中間那長串看起來不像php的東西可以參考呢
謝謝 !

0
e3561025
iT邦新手 5 級 ‧ 2021-10-10 17:16:05

$hero_id = $DAO->getLastId; // 可以拿到他自動建立的 id
echo $DAO->getLastSql; // 想知道會轉換成什麼語法 可以印出來看看

這兩行後面有少小括號,加上去後就不會有報錯了

$hero_id = $DAO->getLastId(); // 可以拿到他自動建立的 id
echo $DAO->getLastSql(); // 想知道會轉換成什麼語法 可以印出來看看

0
eric19740521
iT邦新手 1 級 ‧ 2023-09-06 05:22:19

它存在一個問題??
資料庫帳號/密碼錯誤時??(這個當然屬於用戶設定上的問題??但還是要避免)

他會跳出這樣的錯誤訊息!!
直接在 mysqli_connect 這行就出錯了!!!

Fatal error: Uncaught mysqli_sql_exception: Access denied for user 'root'@'localhost' (using password: YES) in D:\laragon\www\sandbox-mcart\DatabaseAccessObject.php:22 Stack trace: #0 D:\laragon\www\sandbox-mcart\DatabaseAccessObject.php(22): mysqli_connect('localhost', 'root', 'password') #1 D:\laragon\www\sandbox-mcart\test01.php(9): DatabaseAccessObject->__construct('localhost', 'root', 'password', 'game') #2 {main} thrown in D:\laragon\www\sandbox-mcart\DatabaseAccessObject.php on line 22

mysqli_connect_errno() 根本不會執行!!!?

如果是API方式,存取!!那錯誤訊息,不會顯示出來喔!!!因為停在mysqli_connect...

我要留言

立即登入留言