ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
5.0的数据库抽象访问层(我们后面用Db类表示)和模型是一个整体,共同完成了ThinkPHP5.0的ORM(对象关系映射)。 Db和模型最明显的一个区别就是Db查询返回的数据类型为数组(对于一个没有业务逻辑的数据而言,数组已经足够),而模型的查询返回类型的是模型对象实例。 Db类已经非常的强大,但缺点是: * 不支持ActiveRecord实现; * 缺乏灵活的事件机制; * 数据自动处理能力弱; * 数据关联操作繁琐并且不直观; * 不能单独封装业务逻辑; 还有很多...当然,原因并不是否定Db类的实现,因为Db和模型本来就是一个整体,只是各自的职责和分工不同,如果没有Db类的基石,模型也只是建在沙滩上的城堡罢了。 因此Db和模型的存在只是ThinkPHP5.0架构设计中的职责和定位不同,Db负责的只是数据(表)访问,模型负责的是业务数据和业务逻辑。 如果你用框架只是用来管理一些数据的CURD而没有业务需要(其实本质上来说任何的系统都是CURD,业务逻辑都是抽象和封装出来的,这是设计层面的问题了),那么Db类也许已经够用了,但是作为一个业务系统或者平台(无论是WEB还是API),通常每个数据表就对应了一个业务模型对象,甚至存在和其它业务模型的混合和关联逻辑。 举个用户表的例子,用户登录这样一个业务逻辑其实包含了很多的关联操作,你得检查用户账号是否正常,用户名和密码是否正确,然后记录用户的最后登录时间和IP(如果IP所在区域不符有些系统还需要给用户发邮件提醒),还要给用户增加积分,甚至可能还需要检查用户的权限,那么Db类就显得吃力了,这其实也是数组存储结构和对象存储设计的差异,业务越复杂,这种差异越明显。 当然,模型层可以分的更细,把数据模型和逻辑模型,甚至服务模型分开,这个暂时就不在目前的讨论范畴了,只不过把模型层的职责和分工更细化。 想要掌握模型,必须明白和理解下面几个原则: 1. 模型和数据库层的定位和职责不同; 2. 不要因为性能而放弃使用模型,那是得不偿失的; 3. **用面向对象的方式来使用和设计模型;** 4. 模型的数据底层操作仍然是数据库抽象访问层,而且是自动的; 模型设计基于数据访问层之上,并作了更高层次的封装,实现了Db类本身不支持的功能,或者简化了原本使用Db类的复杂操作。从查询操作的角度来看,可以理解为**Db类是数据表的查询构造器,而模型是业务模型的查询构造器**,其实都属于查询构造器的范畴。 在控制器中永远调用的是模型类,然后在模型类中封装业务逻辑方法和数据处理,完成业务操作。**对控制器来说,模型就是一个业务逻辑接口**,并且善于运用依赖注入机制来绑定模型对业务操作会带来极大的便利。 模型定义阶段要达成的目的: 1. 定义数据表(默认就是模型类名) 2. 定义数据表主键(默认会自动获取) 3. 定义数据库连接(默认使用数据库配置) 4. 定义数据处理逻辑(包括属性和方法) 5. 定义业务逻辑(方法) 大多数情况下,数据表和数据库连接是不需要定义的,数据处理逻辑和业务逻辑才是模型定义的重点,如果你发现你的大多数模型类都是什么都没定义,那么就要思考下哪里出问题了,为什么你的模型成了形式和摆设。是没业务需要还是职责分工有问题了? 一个模型并不总是对应一个数据表(例如关联模型和聚合模型),但大多数情况下对应的是一个数据表,默认的对应关系是:模型类的名称(注意不一定是类名,后面会解释)转换为小写和下划线就是对应的数据表: |模型名 |对应数据表| | --- | --- | |User|user | |UserType|user_type | 如果你的数据库配置定义了前缀(假设数据库的前缀定义是 think_),那么对应关系就是: |模型名|对应数据表| | --- | --- | |User |think_user| |UserType|think_user_type| 模型的设计允许给单独指定数据库连接,也就说你可以将不同的数据库的表进行统一的管理,对于跨数据库的应用尤其有用,对于跨库的相同表名,我们可以建立不同名称的模型或者放入不同的命名空间来解决。 指定模型的单独数据库连接方法如下: ~~~ <?php namespace app\index\model; use think\Model; class User extends Model { protected $name = 'user_info'; protected $connection = 'db_config'; } ~~~ 和Db类的connect方法一样,模型类的connection属性允许使用数组、字符串以及配置参数的方式定义,这里使用配置参数(在应用或者模块的配置文件中单独配置db_config参数)的方式,避免在模型里面写死数据库连接信息,全部交给配置文件去统一处理。 如果connection属性使用数组方式配置,会和数据库配置文件中的参数合并,因此你只需要定义有区别的参数,而无需定义全部的数据库参数。 模型调用 模型支持实例化调用和静态调用(主要是查询,查询后会返回一个模型对象实例)。 ~~~ // 实例化User模型 $user = new \app\index\model\User(); // 直接静态查询 $user = \app\index\model\User::get(1); ~~~ 如果你觉得每次引入比较麻烦,系统还提供了一个助手函数帮助你快速实例化模型类而不必每次引入模型类。 你可以在任何地方使用 ~~~ $user = model('User'); ~~~ 实例化User模型类,并且model函数采用单例实现,多次调用不会重复实例化。 我们还是建议使用use方式引入模型类后操作,因为助手函数并不支持模型的静态调用,这个后面我们还会详细说明。