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

PHP 連接 MySQL 兩大擴充比較:mysqli 與 PDO,含亂碼解決方案

     編輯:PHP 相關知識

前言

PHP 連接 MySQL 主流有兩種擴充:mysqli(MySQL Improved,僅支援 MySQL)與 PDO(PHP Data Objects,支援多種資料庫)。本文比較兩者語法、預處理、錯誤處理差異,並詳細解決跨平台中文亂碼問題。

環境檢查與啟用擴充

; php.ini
extension=mysqli
extension=pdo_mysql

; 確認 extension_dir 指向正確的 ext 目錄
; Windows: extension_dir = "ext"
; Linux:   extension_dir = "/usr/lib/php/extensions/no-debug-non-zts-20220829"

; 重啟 Web 伺服器 / PHP-FPM 後驗證
php -m | grep -E 'mysqli|pdo_mysql'

mysqli 面向物件風格範例

<?php
$mysqli = new mysqli('127.0.0.1', 'user', 'password', 'dbname', 3306);

// 連線錯誤處理
if ($mysqli->connect_errno) {
    die("連線失敗: {$mysqli->connect_error}");
}

// 關鍵:設定字元集,防止中文亂碼
$mysqli->set_charset('utf8mb4'); // 推薦 utf8mb4 支援 Emoji

// 查詢
$sql = "SELECT id, name, email FROM users ORDER BY id DESC";
$result = $mysqli->query($sql);

if ($result) {
    while ($row = $result->fetch_assoc()) {
        echo "ID: {$row['id']}, Name: {$row['name']}, Email: {$row['email']}<br>";
    }
    $result->free(); // 釋放結果集
}

// 預處理防止 SQL 注入
$stmt = $mysqli->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param('ss', $name, $email);
$name = '張三'; $email = 'zhang@example.com';
$stmt->execute();
echo "新增 ID: {$stmt->insert_id}";

$mysqli->close();
?>

PDO 範例(推薦新專案使用)

<?php
$dsn = 'mysql:host=127.0.0.1;dbname=dbname;charset=utf8mb4';
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // 拋出例外
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // 關聯陣列
    PDO::ATTR_EMULATE_PREPARES   => false,                  // 使用真實預處理
];

try {
    $pdo = new PDO($dsn, 'user', 'password', $options);

    // 查詢
    $stmt = $pdo->query("SELECT id, name FROM users LIMIT 10");
    foreach ($stmt as $row) {
        echo "{$row['id']}: {$row['name']}<br>";
    }

    // 預處理
    $stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
    $stmt->execute(['李四', 'li@example.com']);
    echo "新增 ID: {$pdo->lastInsertId()}";

    // 交易
    $pdo->beginTransaction();
    $pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
    $pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
    $pdo->commit();

} catch (PDOException $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    die("資料庫錯誤: {$e->getMessage()}");
}
?>

mysqli vs PDO 快速比較

特性mysqliPDO
資料庫支援僅 MySQL/MariaDB12+ 驅動
API 風格面向物件 + 程序式純面向物件
預處理支援 (bind_param)支援 (bindValue/execute)
命名參數不支援支援 (:name)
交易控制begin_transaction()beginTransaction()
錯誤模式手動檢查或 mysqli_report例外模式 (預設可配置)
效能略快 (原生)極微差距,可忽略

中文亂碼根因與徹底解決

亂碼發生鏈路

  1. 資料表/欄位字元集:CHARSET=utf8mb4
  2. 連線字元集:SET NAMES utf8mb4 / mysqli::set_charset / PDO DSN charset
  3. PHP 內部編碼:腳本檔案儲存為 UTF-8 無 BOM
  4. HTML 輸出編碼:<meta charset="utf-8"> / header('Content-Type: text/html; charset=utf-8')

任一環節不匹配即產生亂碼。

統一配置清單

# 1. 資料庫建表
CREATE TABLE t (c VARCHAR(100)) CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

# 2. PHP 連線 (mysqli)
$mysqli->set_charset('utf8mb4');

# 3. PHP 連線 (PDO)
$dsn = 'mysql:host=...;dbname=...;charset=utf8mb4';

# 4. PHP 檔案編碼
; 編輯器設定 "UTF-8 without BOM"

# 5. HTTP 輸出
header('Content-Type: text/html; charset=utf-8');
; 或 nginx/apache 設定
add_header Content-Type "text/html; charset=utf-8";

舊專案 GBK/Big5 遷移建議

  • 資料庫:ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  • 連線:暫時用 SET NAMES gbk 讀取舊資料,寫入前 iconv('GBK','UTF-8',$str) 轉碼,漸進式遷移。
  • 前端:確保瀏覽器接收 UTF-8,避免雙重編碼。

常見錯誤與排查

  • Class 'mysqli' not found → 未啟用 extension=mysqli 或 extension_dir 錯誤。
  • Authentication plugin 'caching_sha2_password' not supported → PHP 版本過舊或 MySQL 8.0 預設插件不支援,建議建立用戶指定 mysql_native_password 或升級 PHP。
  • MySQL server has gone away → 連線逾時,需實作重連邏輯或調大 wait_timeout。

總結

新專案首選 PDO:支援多資料庫、命名參數、例外錯誤模式、真實預處理。mysqli 適合僅針對 MySQL 的高效能舊專案維護。亂碼核心在於「連線字元集」與「資料庫字元集」一致,統一使用 utf8mb4 並從資料庫、連線、PHP、HTML 四層落實,即可徹底杜絕中文亂碼。

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