企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[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.kancloud.cn/zmwtp/tp5/120196)