[TOC]
* * * * *
## 1 模型基類文件分析(thinkphp/library/think/Model.php)
>[info] 成員變量
~~~
操作狀態標記:1新增2更新3全部
const MODEL_INSERT = 1;
const MODEL_UPDATE = 2;
const MODEL_BOTH = 3;
驗證裝有標記:1存在驗證2必須驗證3有值驗證
const EXISTS_VALIDATE = 0;
const MUST_VALIDATE = 1;
const VALUE_VALIDATE = 2;
數據庫操作對象,對象池,主鍵,表前綴
protected $db = null;
private $links = [];
protected $pk = null;
protected $tablePrefix = null;
模型名稱,數據庫名稱,數據庫配置,
protected $name = '';
protected $dbName = '';
protected $connection = [];
無前綴數據表名,帶前綴實際數據表名
protected $tableName = '';
protected $trueTableName = '';
錯誤信息,字段信息,數據信息,數據副本
protected $error = '';
protected $fields = [];
protected $data = [];
protected $duplicate = [];
查詢表達式,命名范圍,字段映射,字段驗證
protected $options = [];
protected $scope = [];
protected $map = [];
protected $rule = [];
~~~
>[info] 58個public方法
* * * * *
> 構造函數
`public function __construct($name = '', array $config = [])`
> __set() __get() __isset() __unset() 數據對象$data的值
`public function __set($name, $value)`
`public function __get($name)`
`public function __isset($name)`
`public function __unset($name)`
> __call()調用內置方法
`public function __call($method, $args)`
> add() addAll() 添加數據
`public function add($data = '', $replace = false)`
`public function addAll($dataList, $options = [], $replace = false)`
> save() 更新數據
`public function save($data = '')`
> delete()刪除數據
`public function delete($options = [])`
> select() 查詢多條數據
`public function select($options = [])`
> getField()獲取字段的值
`public function getField($field, $sepa = null)`
> setFiled() 設置字段的值
`public function setField($field, $value = '')`
> setInc() 自增更新
`public function setInc($field, $step = 1, $lazyTime = 0)`
> setDec() 自減更新
`public function setDec($field, $step = 1, $lazyTime = 0)`
> buildSql() 生成查詢sql
`public function buildSql()`
> find() 獲取單行數據
`public function find($options = [])`
> create() 使用post數據創建數據對象,并經過自動驗證,自動填充,數據過濾。
`public function create($data = '')`
> data() 創建數據對象,沒有自動驗證,自動填充,數據過濾等
`public function data($data = '')`
> db() 切換當前數據庫
`public function db($linkId = '', $config = '')`
> getModelName() 獲取模型名稱
`public function getModelName()`
> getTableName() 獲取表名稱
`public function getTableName()`
> getError() 返回模型的錯誤信息
`public function getError()`
> getDbError 返回數據庫的錯誤信息
`public function getDbError()`
> getlastInsID() 返回最后插入的ID
`public function getLastInsID()`
> getLastSql() 返回最后執行的Sql語句
`public function getLastSql()`
> getPk() 獲取數據表主鍵名稱
`public function getPk($tableName = '')`
> getFields() 獲取數據表字段信息
`public function getFields($tableName = '')`
> getTableInfo() 獲取數據表信息
`public function getTableInfo($fetch = '', $tableName = '')`
> query() sql查詢
`public function query($sql, $bind = [])`
> execute() sql執行
`public function execute($sql, $bind = [])`
> _join() sql組裝
`public function _join($join, $type = 'INNER')`
> join() 組裝join的sql
`public function join($join, $condition = null, $type = 'INNER')`
> union() 組裝union的sql
`public function union($union, $all = false)`
> cache() 數據查詢緩存
`public function cache($key = true, $expire = null, $type = '')`
> field() 指定查詢字段
`public function field($field, $except = false)`
> scope() 調用命名范圍
`public function scope($scope = '', $args = null)`
> where() 生成where語句
`public function where($where)`
> limit() 生成limit語句
`public function limit($offset, $length = null)`
> page() 生成page語句
`public function page($page, $listRows = null)`
> table() 指定數據表
`public function table($table)`
> using() USING支持,多表刪除
`public function using($using)`
> order() 生成order語句
`public function order($field, $order = null)`
> group() 生成group語句
`public function group($group)`
> having() 生成having語句
`public function having($having)`
> lock() 查詢鎖定
`public function lock($lock = false)`
> distinct() 查詢唯一
`public function distinct($distinct)`
> alias() 數據表別名
`public function alias($alias)`
> filter() 寫入過濾方法
`public function filter($filter)`
> index()生成索引
`public function index($index)`
> force() 指定強制索引
`public function force($force)`
> bind() 參數綁定
`public function bind($key, $value = false)`
> comment() 生成注釋
`public function comment($comment)`
> fetchSql() 生成并返回sql語句,
`public function fetchSql($fetch = true)`
> map() 設置字段映射
`public function map($map, $name = '')`
> validate() 設置字段驗證
`public function validate($field = true, $rule = null)`
> auto() 設置字段自動完成
`public function auto($field = true, $rule = null)`
> master() 設置從主服務器讀取數據
`public function master()`
>[info] 27個protected方法
* * * * *
> _initialize() 初始化模型回調方法
`protected function _initialize()`
> _write_data() 數據寫入前回調處理數據,主要進行數據副本對比,字段映射修改,數據自動驗證,數據自動填充,檢查非數據字段,安全過濾,并調用_before_write()回調方法
`protected function _write_data($data, $type)`
> _before_write() 數據寫入前回調處理數據
`protected function _before_write(&$data)`
> _before_insert() 數據寫入前 回調處理內容
`protected function _before_insert(&$data, $options = [])`
> _after_insert() 數據寫入后回調處理
`protected function _after_insert($data, $options = [])`
> _before_update() 數據更新前回調處理
`protected function _before_update(&$data, $options = [])`
> _after_update() 數據更新后回調處理
`protected function _after_update($data, $options = [])`
> _after_delete() 數據刪除后回調處理
`protected function _after_delete($data, $options = [])`
> _after_select() 數據查詢后回調處理
`protected function _after_select(&$resultSet, $options = [])`
> _after_find() 數據查詢后回調處理
`protected function _after_find(&$result, $options = [])`
>_read_data_list() 查詢返回數據的回調處理
`protected function _read_data_list($resultSet, $options)`
> _read_data() 查詢返回數據的回調處理
`protected function _read_data($data, $options = [])`
>_create_filter() 創建post數據對象后的過濾方法
`protected function _create_filter(&$data)`
> _after_db() 數據切換后回調方法
`protected function _after_db()`
> parseSql() 解析sql語句
`protected function parseSql($sql)`
> parseSqlTable() 解析sql語句中的數據表名
`protected function parseSqlTable($sql)`
> parsePKWhere() 主鍵查詢條件解析
`protected function parsePkWhere(&$options)`
> lazyWrite() 延遲更新檢查
`protected function lazyWrite($guid, $step, $lazyTime)`
> dataValidate()數據驗證
`protected function dataValidate(&$data)`
> dataFill() 數據自動填充
`protected function dataFill(&$data)`
> getDatabValue() 從$data獲取$key對應值
`protected function getDataValue($data, $key)`
> getDataRule() 獲取數據自動驗證規則
`protected function getDataRule($rules, $type)`
> autoOperation() 數據自動填充處理
`protected function autoOperation($key, $val, &$data, $options = [])`
> checkValidate() 驗證字段規則
`protected function checkValidate($value, $val, &$data)`
> _parseOptoons() 分析表達式
`protected function _parseOptions($options = [])`
> _parseType() 數據類型檢查和自動轉換
`protected function _parseType(&$data, $key, &$bind, $tableName = '')`
## 2 數據模型文件
>[info] 數據模型涉及的文件及其意義
thinkphp/library/think/Model.php 基礎模型文件
thinkphp/library/think/Db.php 數據庫抽象層文件
thinkphp/library/think/model/ 基礎模型的擴展模型目錄
thinkphp/library/think/model/Adv.php 高級模型文件
thinkphp/library/think/model/MongoModel.php MongoModel模型文件
thinkphp/library/think/model/Relation.php Realation模型文件
thinkphp/library/think/model/View.php View模型文件
thinkphp/library/think/db/ 數據庫適配驅動目錄
thinkphp/library/think/db/Driver.php PDO封裝驅動文件
thinkphp/library/think/db/driver/Mongo.php Mongo數據庫適配驅動文件
thinkphp/library/think/db/driver/Mysql.php Mysql數據庫適配驅動文件
thinkphp/library/think/db/driver/Oracle.php Oracle數據庫適配驅動文件
thinkphp/library/think/db/driver/Pgsql.php Pgsql數據庫適配驅動文件
thinkphp/library/think/db/driver/Sqlite.php Sqlite數據庫適配驅動文件
thinkphp/library/think/db/driver/Sqlsrv.php Sqlsrv數據庫適配驅動文件
>[info] 數據庫的配置
在全局配置文件與應用配置文件都可以定義。
應用配置文件會覆蓋全局配置文件。
還可以在應用的不同模塊中定義各自的數據庫配置。
thinkphp/convention.php 數據庫全局默認配置
~~~
'db_fields_strict' => true,
'database' => [
// 數據庫類型
'type' => 'mysql',
// 數據庫連接DSN配置
'dsn' => '',
// 服務器地址
'hostname' => 'localhost',
// 數據庫名
'database' => '',
// 數據庫用戶名
'username' => 'root',
// 數據庫密碼
'password' => '',
// 數據庫連接端口
'hostport' => '',
// 數據庫連接參數
'params' => [],
// 數據庫編碼默認采用utf8
'charset' => 'utf8',
// 數據庫表前綴
'prefix' => '',
// 數據庫調試模式
'debug' => false,
// 數據庫部署方式:0 集中式(單一服務器),1 分布式(主從服務器)
'deploy' => 0,
// 數據庫讀寫是否分離 主從式有效
'rw_separate' => false,
// 讀寫分離后 主服務器數量
'master_num' => 1,
// 指定從服務器序號
'slave_no' => '',
],
~~~
application/database.php 數據庫應用配置
~~~
return [
// 數據庫類型
'type' => 'mysql',
// 數據庫連接DSN配置
'dsn' => '',
// 服務器地址
'hostname' => '127.0.0.1',
// 數據庫名
'database' => '',
// 數據庫用戶名
'username' => 'root',
// 數據庫密碼
'password' => '',
// 數據庫連接端口
'hostport' => '',
// 數據庫連接參數
'params' => [],
// 數據庫編碼默認采用utf8
'charset' => 'utf8',
// 數據庫表前綴
'prefix' => '',
// 數據庫調試模式
'debug' => APP_DEBUG,
// 數據庫部署方式:0 集中式(單一服務器),1 分布式(主從服務器)
'deploy' => 0,
// 數據庫讀寫是否分離 主從式有效
'rw_separate' => false,
// 讀寫分離后 主服務器數量
'master_num' => 1,
// 指定從服務器序號
'slave_no' => '',
];
~~~
## 2 文件分析
>[info] 1 根據配置文件可知,**框架默認使用mysql數據庫**
>[info] 2 Model.php的構造方法__construct()中**創建連接數據庫的對象**
~~~
public function __construct($name = '', array $config = [])
{
$this->_initialize();
if (!empty($name)) {
$this->name = $name;
} elseif (empty($this->name)) {
$this->name = $this->getModelName();
}
if (strpos($this->name, '.')) {
list($this->dbName, $this->name) = explode('.', $this->name);
}
if (!empty($config['prefix'])) {
$this->tablePrefix = $config['prefix'];
} elseif (isset($config['prefix']) && '' === $config['prefix']) {
$this->tablePrefix = '';
} elseif (is_null($this->tablePrefix)) {
$this->tablePrefix = Config::get('database.prefix');
}
if (!empty($config['connection'])) {
$this->connection = $config['connection'];
}
if (!empty($config['table_name'])) {
$this->tableName = $config['table_name'];
}
if (!empty($config['true_table_name'])) {
$this->trueTableName = $config['true_table_name'];
}
if (!empty($config['db_name'])) {
$this->dbName = $config['db_name'];
}
$this->db(0, $this->connection);
}
~~~
> $name:創建的模型名稱,通常對應數據表名,也可以對應模型文件名稱
> $config:數據庫連接配置選項
` $this->_initialize();`
自定義模型初始化回調內容。可以在這里添加創建模型時調用的內容
~~~
if (!empty($name)) {
$this->name = $name;
} elseif (empty($this->name)) {
$this->name = $this->getModelName();
}
if (strpos($this->name, '.')) {
list($this->dbName, $this->name) = explode('.', $this->name);
}
~~~
獲取待創建模型名稱。
~~~
if (!empty($config['prefix'])) {
$this->tablePrefix = $config['prefix'];
} elseif (isset($config['prefix']) && '' === $config['prefix']) {
$this->tablePrefix = '';
} elseif (is_null($this->tablePrefix)) {
$this->tablePrefix = Config::get('database.prefix');
}
~~~
獲取表前綴配置
~~~
if (!empty($config['connection'])) {
$this->connection = $config['connection'];
}
if (!empty($config['table_name'])) {
$this->tableName = $config['table_name'];
}
if (!empty($config['true_table_name'])) {
$this->trueTableName = $config['true_table_name'];
}
if (!empty($config['db_name'])) {
$this->dbName = $config['db_name'];
}
~~~
獲取數據庫鏈接選項信息
`$this->db(0, $this->connection);`
調用Model->db()方法創建數據庫連接對象
>[info] 3 db()方法根據數據庫鏈接選項信息,調用Db::connect(),創建數據庫連接對象
~~~
public function db($linkId = '', $config = '')
{
if ('' === $linkId && $this->db) {
return $this->db;
}
if (!isset($this->links[$linkId])) {
if (is_string($linkId) && '' == $config) {
$config = Config::get($linkId);
}
$this->links[$linkId] = Db::connect($config);
} elseif (null === $config) {
$this->links[$linkId]->close(); // 關閉數據庫連接
unset($this->links[$linkId]);
return;
}
$this->db = $this->links[$linkId];
$this->_after_db();
return $this;
}
~~~
> $linkId: 數據庫連接對象緩存標識,已創建的數據庫連接對象保存在Model->links變量中,減少數據庫連接的創建次數。
> $config: 數據庫連接配置參數信息
接上文$db->(0,$this->connection).
~~~
if ('' === $linkId && $this->db) {
return $this->db;
}
~~~
檢查$this->db數據庫鏈接對象是否存在,如果存在直接返回
~~~
if (!isset($this->links[$linkId])) {
if (is_string($linkId) && '' == $config) {
$config = Config::get($linkId);
}
$this->links[$linkId] = Db::connect($config);
}
~~~
根據$linkid檢查$this->links數組是否緩存數據庫鏈接對象
如果不存在,根據配置轉換字符串形式$linkid到數據庫標識id,
調用Db::connect($config)創建數據庫連接對象,并保存到$this->links[$linkid]進行緩存。
`$this->db = $this->links[$linkId];`
切換模型的當前數據庫連接對象
`$this->_after_db();`
數據庫切換后回到方法
`return $this;`
返回$this,實現鏈式操作。
>[info] 4 Db.php的數據庫連接對象創建,Db::connect()創建數據庫連接對象
~~~
public static function connect($config = [])
{
$md5 = md5(serialize($config));
if (!isset(self::$instances[$md5])) {
$options = self::parseConfig($config);
if (empty($options['type'])) {
throw new Exception('db type error');
}
$class = (!empty($options['namespace']) ? $options['namespace'] : '\\think\\db\\driver\\') . ucwords($options['type']);
self::$instances[$md5] = new $class($options);
APP_DEBUG && Log::record('[ DB ] INIT ' . $options['type'] . ':' . var_export($options, true), 'info');
}
self::$instance = self::$instances[$md5];
return self::$instance;
}
~~~
> $config:數據庫鏈接配置
`$md5 = md5(serialize($config));`
將數據庫配置序列號并md5編碼后
作為數據庫連接對象實例Db::$instances數組的鍵名,
用來存儲創建的對象實例,減少連接的創建次數,提高運行效率。
~~~
if (!isset(self::$instances[$md5])) {}
~~~
檢查Db::$instances是否緩存數據庫連接對象
如果沒有,創建對象
~~~
$options = self::parseConfig($config);
if (empty($options['type'])) {
throw new Exception('db type error');
}
~~~
首先解析配置參數獲取數據庫類型$type參數,
$type決定使用哪種數據庫驅動,不可缺少。
~~~
$class = (!empty($options['namespace']) ? $options['namespace'] : '\\think\\db\\driver\\') . ucwords($options['type']);
self::$instances[$md5] = new $class($options);
~~~
然后根據$type,創建thinkphp/library/think/db/driver/下對應類型的驅動對象
這里$type為mysql,因此創建mysql驅動對象。并保存到self::$instances。
`APP_DEBUG && Log::record('[ DB ] INIT ' . $options['type'] . ':' . var_export($options, true), 'info');`
記錄創建連接對象日志
~~~
self::$instance = self::$instances[$md5];
return self::$instance;
~~~
保存到當前連接對象實例self::$instance,并返回
>[info] 5 mysql.php文件內容
thinkphp/library/think/db/driver/Mysql.php中
Mysql類繼承PDO驅動類Dirver實現Mysql數據庫的相關操作。
## 3 總結
以上是think5中數據模型涉及的文件的邏輯關系。
從數據庫配置文件convention.php/database.php開始,
經基礎模型Model.php的構造參數__construct()
到數據庫抽象Db.php的的connect()
最后創建繼承PDO的Dirver類的具體的數據庫驅動Mysql對象。
然后基于數據庫連接對象可以實現數據的增刪改查等功能。
think5在thinkphp/helper.php文件中封裝的M() D()等方法可以簡化數據模型的創建
數據模型的增刪改查操作見使用范例的 [數據模型操作](http://www.hmoore.net/zmwtp/tp5/120196)
- 更新記錄
- 概述
- 文件索引
- 函數索引
- 章節格式
- 框架流程
- 前:章節說明
- 主:(index.php)入口
- 主:(start.php)框架引導
- 主:(App.php)應用啟動
- 主:(App.php)應用調度
- C:(Controller.php)應用控制器
- M:(Model.php)數據模型
- V:(View.php)視圖對象
- 附:(App.php)應用啟動
- 附:(base.php)全局變量
- 附:(common.php)模式配置
- 附:(convention.php)全局配置
- 附:(Loader.php)自動加載器
- 附:(Build.php)自動生成
- 附:(Hook.php)監聽回調
- 附:(Route.php)全局路由
- 附:(Response.php)數據輸出
- 附:(Log.php)日志記錄
- 附:(Exception.php)異常處理
- 框架工具
- 另:(helper.php)輔助函數
- 另:(Cache.php)數據緩存
- 另:(Cookie.php)cookie操作
- 另:(Console.php)控制臺
- 另:(Debug.php)開發調試
- 另:(Error.php)錯誤處理
- 另:(Url.php)Url操作文件
- 另:(Loader.php)加載器實例化
- 另:(Input.php)數據輸入
- 另:(Lang.php)語言包管理
- 另:(ORM.php)ORM基類
- 另:(Process.php)進程管理
- 另:(Session.php)session操作
- 另:(Template.php)模板解析
- 框架驅動
- D:(\config)配置解析
- D:(\controller)控制器擴展
- D:(\model)模型擴展
- D:(\db)數據庫驅動
- D:(\view)模板解析
- D:(\template)模板標簽庫
- D:(\session)session驅動
- D:(\cache)緩存驅動
- D:(\console)控制臺
- D:(\process)進程擴展
- T:(\traits)Trait目錄
- D:(\exception)異常實現
- D:(\log)日志驅動
- 使用范例
- 服務器與框架的安裝
- 控制器操作
- 數據模型操作
- 視圖渲染控制
- MVC開發初探
- 模塊開發
- 入口文件定義全局變量
- 運行模式開發
- 框架配置
- 自動生成應用
- 事件與插件注冊
- 路由規則注冊
- 輸出控制
- 多種應用組織
- 綜合應用
- tp框架整合后臺auto架構快速開發
- 基礎原理
- php默認全局變量
- php的魔術方法
- php命名空間
- php的自動加載
- php的composer
- php的反射
- php的trait機制
- php設計模式
- php的系統時區
- php的異常錯誤
- php的輸出控制
- php的正則表達式
- php的閉包函數
- php的會話控制
- php的接口
- php的PDO
- php的字符串操作
- php的curl
- 框架心得
- 心:整體結構
- 心:配置詳解
- 心:加載器詳解
- 心:輸入輸出詳解
- 心:url路由詳解
- 心:模板詳解
- 心:模型詳解
- 心:日志詳解
- 心:緩存詳解
- 心:控制臺詳解
- 框架更新
- 4.20(驗證類,助手函數)
- 4.27(新模型Model功能)
- 5.4(新數據庫驅動)
- 7.28(自動加載)