首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實戰日誌 Day 1:從環境配置到資料庫類封裝的避坑實錄

     編輯:PHP 相關知識

記錄 PHP 學習/重構的第一天,核心任務:搞定字元編碼、踩過模板引擎坑、嘗試主流框架 DB 類、最終選擇輕量級開源 MySQL 類並深度解析其原始碼。這不只是流水帳,更是一份「從造輪子到懂輪子」的進階筆記。

基礎設施:別讓亂碼毀了心情

第一行有效代碼,永遠是設定編碼:

header('Content-Type: text/html; charset=utf-8');

看似簡單,卻能省去 80% 的「為什麼中文變問號」靈異事件。建議直接寫在統一入口檔案或框架 Bootstrap 階段。

模板引擎初體驗:Smarty 在類別裡「炸」了

嘗試在自定類別中實例化 Smarty,報錯不斷。常見坑點:

  • 目錄路徑(`template_dir`、`compile_dir`、`cache_dir`、`config_dir`)必須是**絕對路徑**且**可寫入**。
  • 類別方法中 `$this->smarty` 若未正確初始化或傳遞,會導致「Call to a member function assign() on null」。
  • 命名空間衝突:若專案使用 PSR-4 自動載入,確保 Smarty 類別正確引入(`use Smarty;`)。

教訓: 框架整合的模板引擎(如 Laravel Blade、ThinkPHP 模板)已處理好上下文環境;若手動整合,請先跑通官方 Demo 再封裝。

框架 DB 類「拔不出來」:BroPHP vs ThinkPHP

想單獨抽離框架的資料庫操作類直接用,發現高度耦合:

框架 核心依賴 剝離難度 結論
BroPHP Config 類、Log 類、Exception 體系、路由常量 ⭐⭐⭐⭐⭐ 幾乎等於移植半個框架
ThinkPHP (早期版本) Think 核心類、Hook 機制、快取驅動 ⭐⭐⭐⭐ 同樣難以獨立運行

框架的 DB 類設計初衷是「在框架生態內好用」,而非「隨處可攜」。這讓我意識到:**輕量級、零依賴的資料庫抽象層**對於中小專案或微服務更具價值。

最終選擇:一個開源 MySQL 類的深度剖析

GitHub 上找到一個星標不錯的 MySQL 類(作者:微涼),支援鏈式操作、事務、預處理雛形。以下是核心架構解讀:

核心屬性設計

class MySQL {
    // 配置屬性
    private $db_mysql_hostname, $db_mysql_username, $db_mysql_password;
    private $db_mysql_database, $db_mysql_port, $db_mysql_charset;

    // 查詢構建器暫存
    private $query_list = [];

    // 執行狀態統計
    public $query_count = 0;
    public $query_start_time;

    // 連線資源
    protected $queryID;
    protected $conn;

    // 事務控制
    protected $transTimes = 0;
    protected $numRows = 0;
    protected $error = '';
}

亮點 1:彈性的建構子支援陣列與標量雙模式

public function __construct($hostname_or_conf, $username, $password, $database, $port = '3306', $char = 'utf8') {
    if (is_array($hostname_or_conf)) {
        // 支援配置陣列注入:['hostname'=>'', 'username'=>'', ...]
        $this->db_mysql_hostname = $hostname_or_conf['hostname'];
        // ... 其他賦值
    } elseif (!empty($hostname_or_conf) || !empty($username) || !empty($password) || !empty($database)) {
        // 支援傳統標量參數
        $this->db_mysql_hostname = $hostname_or_conf;
        // ... 其他賦值
    } else {
        die('configuration error.');
    }
    $this->connect();
}

這種設計兼容了「配置檔陣列」與「硬編碼參數」兩種常見場景,極大提升了類別的複用性。

亮點 2:鏈式操作 (Query Builder 雛形)

public function table($table) { $this->query_list['table'] = $table; return $this; }
public function where($where) { $this->query_list['where'] = $where; return $this; }
public function order($order) { $this->query_list['order'] = $order; return $this; }
public function limit($offset, $length = null) { 
    if (!isset($length)) { $length = $offset; $offset = 0; }
    $this->query_list['limit'] = "limit $offset,$length"; 
    return $this; 
}
public function data($data) { $this->query_list['data'] = $data; return $this; }

每個設定方法回傳 `$this`,實現流暢介面:

$db->table('users')->where('status=1')->order('id desc')->limit(10)->select();

亮點 3:SQL 組裝與執行分離

select()、add()、update()、delete() 負責根據 `$this->query_list` 組裝 SQL 字串,最終委派給 query()(查詢)或 execute()(增刪改)執行。

public function select() {
    $select_sql = 'select ';
    $fields = isset($this->query_list['fields']) ? $this->query_list['fields'] : '*';
    $select_sql .= $fields . ' from `' . $this->query_list['table'] . '` ';
    // 拼接 join, where, group, having, order, limit ...
    return $this->query($select_sql);
}

亮點 4:事務管理的簡易實現

public function startTrans() {
    if ($this->transTimes == 0) mysql_query('START TRANSACTION', $this->conn);
    $this->transTimes++;
}
public function commit() {
    if ($this->transTimes > 0) {
        $result = mysql_query('COMMIT', $this->conn);
        $this->transTimes = 0;
        if (!$result) throw new Exception($this->error());
    }
    return true;
}
public function rollback() {
    if ($this->transTimes > 0) {
        $result = mysql_query('ROLLBACK', $this->conn);
        $this->transTimes = 0;
        if (!$result) throw new Exception($this->error());
    }
    return true;
}

透過計數器 `transTimes` 支援巢狀事務邏輯(雖然 MySQL 本身不支援巢狀事務,但這樣寫能避免重複 COMMIT/ROLLBACK 報錯)。

⚠️ 關鍵遺留問題:基於已棄用的 `mysql_*` 函式庫

原始碼大量使用 `mysql_connect`、`mysql_query` 等,**PHP 7.0+ 已完全移除**。實際專案中**必須遷移至 PDO 或 MySQLi**。這也是為什麼「造輪子」不如「用成熟輪子」(如 `illuminate/database`、Doctrine DBAL、Medoo)的原因。

實際使用範例

// 1. 實例化(支援陣列配置)
$config = [
    'hostname' => '127.0.0.1',
    'username' => 'root',
    'password' => '',
    'database' => 'myly',
    'charset'  => 'utf8'
];
$db = new MySQL($config);

// 2. 鏈式查詢
$list = $db->table('data')->select();

// 3. 新增資料
$db->table('data')->data(['name' => 'Test', 'value' => 123])->add();

// 4. 事務範例
$db->startTrans();
try {
    $db->table('account')->data(['money' => -100])->where('id=1')->update();
    $db->table('account')->data(['money' => +100])->where('id=2')->update();
    $db->commit();
} catch (Exception $e) {
    $db->rollback();
    echo '轉帳失敗:' . $e->getMessage();
}

前端小插曲:jQuery 互動特效

順手記錄一個滑鼠懸停列項變色的片段,純前端無 PHP 相關,但全端工程師常需處理:

$(document).ready(function() {
    $('.content').each(function(index) {
        $(this).hover(
            function() { // mouseenter
                $('.user').eq(index).css('background', '#F8FBFD');
                $('.text').eq(index).css('background', '#FFFDF6');
            },
            function() { // mouseleave
                $('.user').eq(index).css('background', '#E6F0F9');
                $('.text').eq(index).css('background', '#F8FBFD');
            }
        );
    });
});

現代寫法建議改用 CSS `:hover` 偽類或 CSS 變數,將樣式邏輯從 JS 剝離,效能更好且無閃爍。

Day 1 總結與明日計畫

  1. ✅ 環境編碼設定
  2. ⚠️ Smarty 整合受阻,改用原生 PHP 模板或 Twig
  3. ❌ 框架 DB 類耦合度太高,不可單獨使用
  4. ✅ 找到輕量 MySQL 類,但**必須重寫為 PDO/MySQLi 版本**才能上生產
  5. 📝 明日任務:重構該 MySQL 類為 PDO 版本,加入預處理防注入,補全單元測試

核心感悟: 「拿來即用」的代碼往往隱藏技術債。讀懂原始碼、評估依賴、判斷維護成本,才是資深工程師的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved