M方法是TP中最多見的一個模型化沒有文件的Model方法。仔細進行解析的時候,會發現裏面邏輯也是挺多的,這節主要梳理TP框架最多見的M方法。
方法代碼:
function M($name='', $tablePrefix='',$connection='') {
//設立一個靜態變量,能夠在運行過程當中,一直保存的值
static $_model = array();
//若是在裏面找到了:號,就用explode進行分割提取,不然就讀取model
if(strpos($name,':')) {
//M方法實例化的時候,默認狀況下是直接實例化系統的\Think\Model類,
//示例M('\Home\Model\CommonModel:User','think_','db_config');這種通常用的比較少,大多數狀況下用Think\\Model
list($class,$name) = explode(':',$name);
}else{
// 默認的class就是
$class = 'Think\\Model';
}
//鏈接標記數組標記
$guid = (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class;
//沒有模型化將緩存裏面的對象返回出來
if (!isset($_model[$guid]))
$_model[$guid] = new $class($name,$tablePrefix,$connection);
return $_model[$guid];
}
運行邏輯:檢測是否是實例化默認的類,將其放入一個$_model數組中,並給每一個實例化都賦予一個鍵值。
默認執行的類是:
$a = new \Think\Model();
實例化的時候__construct()
public function __construct($name='',$tablePrefix='',$connection='') {
//在自動加載的時候,實現自動初始化,能夠加入用戶本身的斷定邏輯
$this->_initialize();
if(!empty($name)) {
if(strpos($name,'.')) {
// 支持 數據庫名.模型名的 定義
list($this->dbName,$this->name) = explode('.',$name);
}else{
$this->name = $name;
}
}elseif(empty($this->name)){
$this->name = $this->getModelName();
}
// 設置表前綴
if(is_null($tablePrefix)) {// 前綴爲Null表示沒有前綴
$this->tablePrefix = '';
}elseif('' != $tablePrefix) {
$this->tablePrefix = $tablePrefix;
}elseif(!isset($this->tablePrefix)){
$this->tablePrefix = C('DB_PREFIX');
}
// 數據庫初始化操做
// 獲取數據庫操做對象
// 當前模型有獨立的數據庫鏈接信息
$this->db(0,empty($this->connection)?$connection:$this->connection,true);
}
自動加載運行邏輯:初始化模型,將輸入的字段儲存到$this->name和$this->db,而後讀取鏈接信息
默認的數據庫鏈接,數據庫的鏈接配置
public function db($linkNum='',$config='',$force=false) {
if('' === $linkNum && $this->db) {
return $this->db;
}
static $_db = array();
if(!isset($_db[$linkNum]) || $force ) {
// 建立一個新的實例
if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // 支持讀取配置參數
$config = C($config);
}
$_db[$linkNum] = Db::getInstance($config);
}elseif(NULL === $config){
$_db[$linkNum]->close(); // 關閉數據庫鏈接
unset($_db[$linkNum]);
return ;
}
// 切換數據庫鏈接
$this->db = $_db[$linkNum];
$this->_after_db();
// 字段檢測,能夠經過DB_FIELDS_CACHE控制是否緩存數據庫的字段(常常變更字段的,應該禁止掉該參數)
if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo();
return $this;
}
運行邏輯:建立一個配置,切換數據庫鏈接,每次都讀取配置裏面的配置信息進行實例化變更
獲取數據庫的實例:
public static function getInstance($db_config='') {
static $_instance = array();
//生成一個惟一的鍵值,用儲存
$guid = to_guid_string($db_config);
if(!isset($_instance[$guid])){
$obj = new Db();
$_instance[$guid] = $obj->factory($db_config);
}
return $_instance[$guid];
}
加載驅動進行控制:
public function factory($db_config='') {
// 讀取數據庫配置
$db_config = $this->parseConfig($db_config);
if(empty($db_config['dbms']))
E(L('_NO_DB_CONFIG_'));
// 數據庫類型
if(strpos($db_config['dbms'],'\\')){
$class = $db_config['dbms'];
}else{
$dbType = ucwords(strtolower($db_config['dbms']));
$class = 'Think\\Db\\Driver\\'. $dbType;
}
// 檢查驅動類
if(class_exists($class)) {
$db = new $class($db_config);
}else {
// 類沒有定義
E(L('_NO_DB_DRIVER_').': ' . $class);
}
return $db;
}
運行邏輯:根據配置讀取對應的數據庫控制驅動(經常使用的mysql或者mysqli驅動等)
整理後M的運行邏輯流程以下:(M('user')流程)
實例化model-》自動加載實現(獲取到name,dbname,db等)——》$this->db根據當前配置去實例化對應的Db類
——》Db類里根據當前的配置去找到對應的數據庫驅動,同時進行實例化返回——》返回$this,進行其餘的操做
M的幾種用法展現:
1.$Model = M();
//進行原生的SQL查詢
$Model->query('SELECT * FROM think_user WHERE status = 1');
2.M('\Home\Model\CommonModel:User','think_','db_config');mysql