現實專案中常遇到非標準命名的資料表 (如 CMS 系統的 cow_archives_4、分表 order_202401、第三方系統同步表)。ThinkPHP 通過 protected $tableName 屬性提供靈活映射,本文系統梳理定義規則、進階技巧與避坑指南。
<?php
// Application/Common/Conf/config.php
return [
'DB_PREFIX' => 'cow_', // 所有表自動加此前綴
];
<?php
// Application/Home/Model/Archives4Model.class.php
namespace Home\Model;
use Think\Model;
class Archives4Model extends Model {
// 關鍵:去除前綴後的表名 (不含 cow_)
protected $tableName = 'archives_4';
// 可選:指定主鍵 (非 id 時)
protected $pk = 'aid';
// 可選:自動驗證/完成規則
protected $_validate = [
['title', 'require', '標題不能為空'],
['title', '', '標題已存在', self::EXISTS_VALIDATE, 'unique'],
];
}
<?php
// D 方法自動解析模型名 -> Archives4Model
$archives = D('Archives4');
// 查詢
$list = $archives->where(['status'=>1])->order('id DESC')->limit(10)->select();
// 新增 (自動填充 create_time 等)
$data = ['title' => '測試', 'content' => '內容'];
$archives->create($data);
$archives->add();
// 連表查詢 (需在模型定義 _link)
$archives->relation(true)->select();
<?php
class OrderModel extends Model {
protected $tableName = 'order'; // 基礎表名
// 根據年月動態切換表
public function setTableByDate(string $yearMonth): self {
$this->tableName = "order_{$yearMonth}";
return $this; // 支援鏈式調用
}
}
// 使用
$order = D('Order')->setTableByDate('202401')->where(['uid'=>123])->select();
<?php
// 完全自定義表名 (忽略 DB_PREFIX)
class LogModel extends Model {
protected $tableName = 'system_logs'; // 實際表名 system_logs
protected $tablePrefix = ''; // 關鍵:覆蓋全局前綴為空
}
<?php
class ExternalUserModel extends Model {
// 指定使用 'db2' 連接配置
protected $connection = 'DB_CONFIG2';
protected $tableName = 'users';
protected $tablePrefix = 'ext_';
// config.php 需定義
// 'DB_CONFIG2' => ['db_type'=>'mysql', 'db_host'=>'...', ...]
}
<?php
class ArticleModel extends Model {
protected $tableName = 'archives_4';
protected $_link = [
'category' => [
self::BELONGS_TO,
'Category', // 對應 CategoryModel
'foreign_key' => 'cid', // 本表外鍵
'parent_key' => 'id', // 關聯表主鍵
],
'tags' => [
self::MANY_TO_MANY,
'Tag', // TagModel
'article_tag', // 中間表名 (去前綴)
'foreign_key' => 'article_id',
'relation_key' => 'tag_id',
],
];
}
| 現象 | 原因 | 解決 |
|---|---|---|
| SQL 錯誤: Table 'db.cow_archives_4' doesn't exist | 雙重加前綴 | 檢查 $tableName 是否已包含前綴,應只寫去前綴後的名稱 |
| D('Archives4') 找不到模型 | 命名不符合規範 | 類名必須為 Archives4Model,檔案 Archives4Model.class.php |
| 關聯查詢報錯 Base table not found | 中間表名未去前綴 | _link 中的中間表名寫去前綴名 (如 article_tag) |
| 跨庫查詢失敗 | 連接配置名錯誤 | $connection 需匹配 config.php 中的配置鍵名 (如 DB_CONFIG2) |
{Business}{Suffix}Model,表名去前綴蛇形 business_suffix。BaseModel 統一處理 $tablePrefix、$connection、軟刪除、時間戳自動寫入等通用邏輯。@property、@method 註解為動態屬性/方法提供智能提示。| 特性 | ThinkPHP 3.2 | ThinkPHP 5/6/8 |
|---|---|---|
| 模型基類 | Think\Model | think\Model |
| 表名屬性 | protected $tableName | protected $table (或 protected $name) |
| 前綴屬性 | protected $tablePrefix | protected $prefix |
| 實例化 | D('ModelName') | model('ModelName') 或 new ModelName() |
| 查詢構建器 | where()->order()->limit() | 同樣支援,更推薦 where()->order()->paginate() |
非標準表名映射是 ThinkPHP 適應複雜現有資料庫的核心能力。掌握 $tableName/$table、$tablePrefix/$prefix、$connection 三大屬性組合,配合基類封裝與命名規範,即可優雅處理分表、跨庫、第三方表等各類場景,避免在控制器中硬編碼 SQL 破壞 MVC 分層。