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

Yii 動態模型實作:執行期指定資料表名稱支援機制分析

     編輯:PHP 綜合知識

背景動機

Yii 1.x 的 ActiveRecord 採用靜態模型對應資料表,需預先為每張表建立 Model 類別。但實務上常遇到:動態建立的資料表、單純資料顯示無需驗證、讀寫分離需不同模型等情境,需要執行期動態指定表名操作資料。

解決方案:DTable 動態模型類別

將以下 DTable.php 放入 protected/models/ 目錄,即可在任何位置以動態表名操作資料。

<?php
/**
 * DTable - Yii 動態資料表模型
 * @author zhangxugg@163.com
 * @since Yii 1.1.10
 */
class DTable extends CActiveRecord {
    private static $tableName;

    public function __construct($table_name = '') {
        if ($table_name === null) {
            parent::__construct(null); // 供 model() 靜態呼叫用
        } else {
            self::$tableName = $table_name;
            parent::__construct();
        }
    }

    public static function model($table_name = '') {
        self::$tableName = $table_name;
        return parent::model(__CLASS__);
    }

    public function tableName() {
        return self::$tableName;
    }
}
?>

使用範例

建立新記錄

$memo = new DTable('{{memo}}'); // {{}} 會自動替換為表前綴
$memo->msg = 'this is content';
$memo->save();
echo $memo->id; // 取得自動遞增 ID

讀取與更新現有記錄

$memo = DTable::model('{{memo}}')->findByPk(12);
$memo->msg = "modified content";
$memo->save();

切換非預設資料庫連線

// config/main.php 需預先定義 'db-other' 元件
DTable::$db = Yii::app()->getComponent('db-other');
$memo = DTable::model('{{memo}}')->findByPk(12);

核心機制解析

  1. 靜態屬性 $tableName:儲存目前操作的表名,供 tableName() 回傳。
  2. 建構子區分:new DTable('table') 建立新記錄;DTable::model('table') 取得靜態模型實例供查詢。
  3. parent::model(__CLASS__):關鍵在於傳遞 固定類別名 DTable 而非動態表名,確保 Yii 內部快取機制正常運作(以類別名為鍵)。
  4. tableName() 回傳動態表名,完成 AR 與資料表的動態繫結。

限制與注意事項

  • 無屬性定義:動態模型無法預先宣告屬性、規則、關聯,attributes 由資料庫結構自動反映。
  • 無驗證規則:rules() 為空,資料寫入前需自行驗證。
  • 無關聯支援:relations() 為空,無法使用 with()、through 等關聯查詢。
  • 表名注入風險:表名來源若為使用者輸入,必須嚴格白名單驗證,防止 SQL 注入。
  • 快取衝突:同一請求中對不同表使用 DTable 可能導致靜態屬性覆蓋,建議單一請求僅操作單一動態表,或改用實例屬性儲存表名(需覆寫更多方法)。

改進版:實例屬性儲存表名(避免靜態衝突)

class DTable extends CActiveRecord {
    private $tableName;

    public function __construct($table_name = '', $scenario = 'insert') {
        $this->tableName = $table_name;
        parent::__construct($scenario);
    }

    public static function model($table_name = '') {
        $model = new self($table_name, 'model'); // 特殊 scenario 區分
        return $model;
    }

    public function tableName() {
        return $this->tableName;
    }

    // 覆寫 getDbConnection 確保每個實例可用不同連線
    public function getDbConnection() {
        return isset(self::$db) ? self::$db : parent::getDbConnection();
    }
}

適用場景總結

場景建議方案
固定業務資料表標準 GII 產生 Model,完整驗證、關聯、行為
動態建立的日誌/統計表DTable 動態模型
單純資料顯示(後台報表)DTable 或 DAO (createCommand)
跨資料庫同步/遷移DTable + 切換 $db 元件
需關聯查詢的動態表考慮建立基底 Model + 動態設定 tableName()

DTable 為 Yii 1.x 提供了輕量級的動態表操作能力,適用於不需完整 AR 功能的簡單讀寫場景。Yii 2.0 中可直接在 Model 覆寫 tableName() 回傳動態值,或使用 yii\db\ActiveRecord::tableName() 靜態方法搭配參數實現更優雅的動態模型。

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