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');