一、实例化模型
在ThinkPHP2.0及以上版本中,可以无需进行任何模型定义。只有在需要封装单独的业务逻辑时,模型类才是必须定义的,因此ThinkPHP在模型上有很多灵活性和方便性,而不必因为表太多而烦恼
ThinkPHP有几种实例化模型的方法
1、实例化基础模型类
即实例化系统自带的Model类,ThinkPHP会自动帮我们找到数据库中相应的表,并获取其字段(表结构信息)
·$User=new Model('User');
·$User=M('User');(快捷方法,通过M函数)
大写字母与下划线关系(think_是在配置件中设置的表前缀)
实例化基础模型类传递进去的参数在数据库中对应的表名
User think_user
UserMessage think_user_message
ps,因为表前缀中已经有了一个下划线,所以user对应的也是think_user
2、实例化其它模型类
第一种实例化方法因为没有涉及自定义模型类,因此很难封装一些自定义的业务逻辑(因为ThinkPHP自带的基础模型类显然只提供了基本的CRUD操作等等一些操作,肯定是无法满足项目业务逻辑的,所以必须自定义模型类来封装自定义业务逻辑),如果只需要扩展一些通用的(所谓通用,就是多个针对不同表的模型类都需要用到的逻辑)自定义业务逻辑,那么可以采用这种方式
·$User=new CommonModel('User');
·$User=M('User','CommonModel');(快捷方式,通过M函数)
ps,CommonModel类是一个自定义模型类,在应用目录->Lib目录->Model目录->CommonModel.class.php件中
因为ThinkPHP是自动加载模型类的,所以在实例化模型类之前不需要手动模型类件的导入,即不需要require '模型类件';等
自定义模型类必须继承系统自带的模型类(比如说Model类),而且没有别名导入的话,自定义模型类件必须放在应用目录->Lib目录->Model目录下
可以在CommonModel类里面定义一些通用的逻辑方法,就可以省去为每个数据表定义具体的模型类,如果你的项目已经有超过100个数据表了,而大多数情况都是一些基本的CURD操作的话,只是个别模型有一些复杂的业务逻辑需要封装,那么第一种方式和第二种方式的结合是一个不错的选择。
3、实例化自定义模型类
得先定义针对不同表的自定义模型类,比如说UserModel类,UserMessagesModel类等等,然后再进行实例化。这种方式是用的最多的
·$User=new UserModel;
·$User=D('User');(快捷方式,通过D函数),D函数有自动检测自定义模型类的功能,如果应用目录->Lib目录->Model目录下存在所传入参数对应的自定义模型类(即参数User对应于自定义模型类UserModel),那么就会实例化该自定义模型类,否则则实例话系统自带的模型类(Model类)。而且对于已经实例化过的模型不会重复实例化,默认的D函数只能实例化当前应用的模型类,不能跨应用实例化模型类,如果想实例化其它应用的模型类,则可以$User=D('User','其它应用名');,如果启用了模块分组,则可以$Usr=D('其它分组名.User');
ps,这种实例化模型方式与上一种方式有何区别,其实上一种方式最大的特征就是通用。对于一张表,如果你只想对其进行简单的CRUD操作,则采用第一种方式即可;如果你不仅想对其进行简单的CRUD操作,还想用到一些该项目其它表通用的自定义逻辑操作,则采用第二种方式;如果不仅想对其进行CRUD操作,还想用到一些自定义的逻辑操作,而且这些逻辑操作只有该表用到(即不需要用到其它表通用的自定义逻辑操作),则采用第三种方式
4、实例化一个空模型类
如果仅仅是想使用原生SQL的话,不需要使用额外的模型类,可以选择实例化一个空模型类
·$Model=new Model;
·$Model=M;(快捷方式,通过M函数)
比如说$Model->query('SELECT * FROM think_user where status=1');
不管是采用哪一种方式,以及不管是采用new、M或者D进行实例化模型类,都会ThinkPHP都会自动加载数据库连接信息去连接数据库,如果数据库连接失败也是会报错的
关于数据表字段缓存,索引表示表字段,关联表示表的一些属性
如果开启数据表字段缓存,则ThinkPHP是不理会任何有关表结构的修改操作的,也就是说,即使修改了表结构,ThinkPHP也会按照数据表字段缓存件中的表结构对表进行操作,除非手动删除数据表字段缓存件。那么不难看出(并经过测试),ThinkPHP的数据表字段缓存机制是这样的,在进行数据库操作之前,先判断是否开启数据表字段缓存,如果开启,则检索一下应用目录->Runtime目录->Data目录->_field目录中有无相应表的数据表字段缓存件,若有,则加载该件中的表结构,然后对相应表进行操作,若无,则先操作数据库获取到表结构,然后再对相应表进行操作,并将刚才获取到的表结构缓存起来;如果没有开启则直接先操作数据库获取表结构,然后再对相应表进行操作!这段话可以简化成如下代码,O(∩_∩)O哈哈~
当开启_DEBUG(调试模式)之后,模板中的框架集就不能显示了!这是因为Trace等信息是放在<body>中的,而框架集中是不能存在<body>的,从而导致显示一片空白二、模型命名和获取字段
1、关于模型命名
到这里,基本是已经明确了自定义模型名与数据表名之间的对应关系。也就是说,自定义模型类会根据去名称其对相应的表进行操作,那么假如要求自定义模型类不根据其表名对相应的数据表进行操作该怎么办呢(即跨表操作)?答案是可以通过Model类的如下两个属性(protected属性)进行操作
·$tableName
不包含表前后缀的数据表名称,与自定义模型类名(或自带的模型类中实例化时传入的参数)相对应,但是可以修改该属性,来让自定义模型类操作与其名称不对应的表
·$trueTableName
包含表前后缀的数据表名称,默认为null,即数据库中的真实表名
经过测试,三者的优先级应该如下
自定义模型类中自己指定的$trueTableName>自定义模型类中自己指定的$tableName>ThinkPHP自带的模型类中默认的$tableName
也就是说设置了$trueTableName就按$trueTableName的来,否则按$tableName、最后按默认的
除了可以对默认的数据表进行修改之外还可以对默认的数据库进行修改,使用$dbName属性!只有在当前的模型类对应的数据库名称和配置件不同的时候才需要定义,以实现跨库操作
关于表后缀,手册上说的一段话如下
2、获取字段
关于这段逻辑,不知道有想法的同志有没有思考过,就是对数据表进行操作之前必要进行这样的判断和件加载等等操作吗?为啥不直接将表结构信息告诉模型,那么就省去了这么多麻烦,直接对数据表就可以进行操作,显然节省IO开销,并且省掉一次查询数据库获取表结构的数据库操作,提升效率!对,ThinkPHP的设计者也考虑到了这一点,就设计了$field属性
·ThinkPHP的默认认为数据表的主键字段名都是id,并且自动增长
·$User->getPk;可以获取User表的主键
·$User->getDbFields;可以获取User表的所有字段信息