PHP 操作 MySQL 是後端開發的核心技能。早期使用 mysql_* 函數已被棄用(PHP 7.0 移除),現代開發應採用 PDO (PHP Data Objects) 或 MySQLi。本文從基礎連線、資料庫操作,到建立可重用的資料庫類,完整示範現代最佳實踐。
php.ini 已啟用擴充:extension=pdo_mysql、extension=mysqliphp -m | grep -E 'pdo_mysql|mysqli'<?php
$dsn = 'mysql:host=localhost;dbname=guestbook;charset=utf8mb4';
$username = 'root';
$password = '';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 拋出例外
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 回傳關聯陣列
PDO::ATTR_EMULATE_PREPARES => false, // 使用原生預處理
]);
echo "連線成功";
} catch (PDOException $e) {
die("連線失敗: " . $e->getMessage());
}
?>
<?php
// 查詢單筆
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([1]);
$user = $stmt->fetch();
// 查詢多筆
$stmt = $pdo->prepare('SELECT * FROM users WHERE status = ? ORDER BY created_at DESC');
$stmt->execute([1]);
$users = $stmt->fetchAll();
// 新增資料
$stmt = $pdo->prepare('INSERT INTO users (username, email) VALUES (?, ?)');
$stmt->execute(['JohnDoe', 'john@example.com']);
$newId = $pdo->lastInsertId();
// 更新資料
$stmt = $pdo->prepare('UPDATE users SET email = ? WHERE id = ?');
$stmt->execute(['new@example.com', 1]);
// 刪除資料
$stmt = $pdo->prepare('DELETE FROM users WHERE id = ?');
$stmt->execute([1]);
// 事務處理
try {
$pdo->beginTransaction();
$pdo->exec("INSERT INTO logs (msg) VALUES ('操作 A')");
$pdo->exec("INSERT INTO logs (msg) VALUES ('操作 B')");
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
?>
<?php
// 物件導向風格
$mysqli = new mysqli('localhost', 'root', '', 'guestbook');
if ($mysqli->connect_errno) {
die("連線失敗: " . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');
// 預處理查詢
$stmt = $mysqli->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('i', $id);
$id = 1;
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
$stmt->close();
$mysqli->close();
?>
<?php
class Database {
private static ?self $instance = null;
private PDO $pdo;
private function __construct() {
$dsn = 'mysql:host=localhost;dbname=guestbook;charset=utf8mb4';
$this->pdo = new PDO($dsn, 'root', '', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
}
public static function getInstance(): self {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 禁止克隆與反序列化
private function __clone() {}
public function __wakeup() {}
public function getPdo(): PDO {
return $this->pdo;
}
// 便利方法
public function query(string $sql, array $params = []): PDOStatement {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
public function fetchOne(string $sql, array $params = []): ?array {
return $this->query($sql, $params)->fetch();
}
public function fetchAll(string $sql, array $params = []): array {
return $this->query($sql, $params)->fetchAll();
}
public function insert(string $table, array $data): int|false {
$fields = implode(', ', array_keys($data));
$placeholders = ':' . implode(', :', array_keys($data));
$sql = "INSERT INTO {$table} ({$fields}) VALUES ({$placeholders})";
$stmt = $this->pdo->prepare($sql);
$success = $stmt->execute($data);
return $success ? (int)$this->pdo->lastInsertId() : false;
}
}
// 使用方式
$db = Database::getInstance();
$user = $db->fetchOne('SELECT * FROM users WHERE email = ?', ['john@example.com']);
$newId = $db->insert('users', ['username' => 'Jane', 'email' => 'jane@example.com']);
?>
display_errors,記錄至 log。utf8 截斷問題。摒棄過時的 mysql_* 函數,擁抱 PDO 或 MySQLi 的預處理機制,是撰寫安全、可維護 PHP 程式的第一步。封裝 Database 類能進一步提升開發效率,統一錯誤處理與資源管理。