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

PHPLIB 擴展支援多資料庫連線:DB_Sql 類別改造實戰

     編輯:PHP 綜合知識

PHPLIB 的 DB_Sql 類別預設僅支援單一資料庫連線。本文示範如何透過繼承與工廠模式擴展它,實現多資料庫連線管理,並保持向相容 API。

原始限制分析

DB_Sql 建構子固定讀取全域設定 $db_host、$db_database 等,無法在執行期切換連線。專案若需同時操作「訂單庫」、「會員庫」、「日誌庫」,需改造架構。

改造方案:連線池管理器

<?php
// 1. 定義連線設定介面
interface DBConfigProvider {
    public function getConfig(string $name): array;
}

// 2. 實作:從陣列/ini/環境變數載入
class ArrayDBConfig implements DBConfigProvider {
    private $configs;
    public function __construct(array $configs) { $this->configs = $configs; }
    public function getConfig(string $name): array {
        return $this->configs[$name] ?? throw new InvalidArgumentException("Unknown DB: $name");
    }
}

// 3. 擴展 DB_Sql 支援指定連線
class MultiDB_Sql extends DB_Sql {
    private static $instances = [];
    private static $configProvider;

    public static function setConfigProvider(DBConfigProvider $provider) {
        self::$configProvider = $provider;
    }

    // 工廠方法:取得/建立命名連線
    public static function getInstance(string $name = 'default'): self {
        if (!isset(self::$instances[$name])) {
            $cfg = self::$configProvider->getConfig($name);
            $instance = new self();
            $instance->Host     = $cfg['host'];
            $instance->Database = $cfg['database'];
            $instance->User     = $cfg['user'];
            $instance->Password = $cfg['pass'];
            $instance->Type     = $cfg['type'] ?? 'mysql'; // mysql, pgsql, oracle, mssql
            $instance->connect();
            self::$instances[$name] = $instance;
        }
        return self::$instances[$name];
    }

    // 禁止直接 new,強制使用工廠
    protected function __construct() { parent::__construct(); }
    private function __clone() {}
    public function __wakeup() { throw new Exception("Cannot unserialize"); }
}

// 4. 使用範例
MultiDB_Sql::setConfigProvider(new ArrayDBConfig([
    'default' => ['host'=>'localhost','database'=>'main','user'=>'u','pass'=>'p','type'=>'mysql'],
    'orders'  => ['host'=>'db2','database'=>'orders','user'=>'u','pass'=>'p','type'=>'mysql'],
    'logs'    => ['host'=>'db3','database'=>'logs','user'=>'u','pass'=>'p','type'=>'pgsql'],
]));

// 取得不同連線
$mainDB = MultiDB_Sql::getInstance('default');
$orderDB = MultiDB_Sql::getInstance('orders');
$logDB = MultiDB_Sql::getInstance('logs');

$mainDB->query("SELECT * FROM users WHERE id=1");
$orderDB->query("SELECT * FROM orders WHERE user_id=1");
$logDB->query("INSERT INTO access_log (ip, url) VALUES ('1.2.3.4', '/home')");

進階:自動重連與健康檢查


class RobustMultiDB_Sql extends MultiDB_Sql {
    private $lastPing = 0;
    private $pingInterval = 30; // 秒

    public function query($sql) {
        $this->ensureConnected();
        return parent::query($sql);
    }

    private function ensureConnected() {
        if (time() - $this->lastPing > $this->pingInterval) {
            if (!$this->ping()) {
                $this->reconnect();
            }
            $this->lastPing = time();
        }
    }

    private function ping(): bool {
        // 簡易檢查
        return @$this->query('SELECT 1') !== false;
    }

    private function reconnect() {
        $this->connect(); // 父類別方法
    }
}

整合現有 PHPLIB 專案遷移步驟

  1. 建立 MultiDB_Sql 類別檔,置於 phplib/ 目錄
  2. 修改 common.php:移除 require('db_mysql.inc'),改載入新類別
  3. 設定連線配置(建議用 config/db.php 返回陣列)
  4. 全域搜尋 new DB_Sql 或 $db = new DB_Sql,替換為 MultiDB_Sql::getInstance('name')
  5. 測試所有資料庫操作頁面

現代化替代:PDO + 依賴注入容器

PHPLIB 已停止維護。新專案建議直接使用 PDO 搭配 PSR-11 容器(如 PHP-DI、Symfony DI、Laravel Container):


// 容器設定
$container->set('db.main', function() {
    return new PDO('mysql:host=localhost;dbname=main;charset=utf8mb4', 'u', 'p', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
});
$container->set('db.orders', fn() => new PDO('mysql:host=db2;dbname=orders...', ...));

// 使用
$mainDB = $container->get('db.main');
$orderDB = $container->get('db.orders');

此方式無繼承耦合、支援任意驅動、易於測試(Mock PDO)、符合現代 PHP 標準。

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