【Yii Framework】 Model以及数据库层
应用Yii框架已经有一段时间了,之前也分享了一些Yii框架的入门视频,撰写了一些源代码分析文章。随着使用的深入,越发被Yii框架折服,感叹原作者Qiang Xue对于面向对象编程,Web开发,以及PHP的深厚功力和应用能力。众所周知,像一切Web开发框架那样,Yii框架提供ORM功能,中文叫对象关系映射,能将关系型数据库的数据,映射成对象,从而提供了便捷的数据操作能力。
在合作的同事中,听到了一些误解的声音,一个是抱怨Yii框架的Model难用,因为Yii框架的Model从DB中取出数据后,就已经转换成了一个对象了,而不是PHP程序员所熟悉的Array,并且,没有提供相关参数直接取得Array数组。
思辨1:不知道别的框架到底是怎么处理这个部分的,因为MVC模式中,这个M指的正是Model,Yii框架的处理模式,我认为非常恰当,因为如果M只返回了一个Array,那么其实并没有真正的提供Model,而只是把操作DB的过程封装了起来,没有提供这个层次的一种抽象能力,最终还是需要在PHP语言这个层次上解决问题,等于是框架没有在M层提供恰当的抽象机制。
思辨2:Yii框架确实没有提供参数,可以控制直接返回Array,但是Yii框架的Model却保留了Array语法的便捷性,底层的CModel实现了IteratorAggregate, ArrayAccess两个接口,恰恰保留了按照Array语法操作Model的能力,这是何其贴心,按照我个人的风格,是断然不会提供这种东西的,因为这明显是为了照顾那些对面向对象编程非常不适应的程序员。如果非要一个真正的、纯粹的Array,Model还提供了getAttributes方法,可以将一个Model封装的数据,真正的转换成PHP的关联数组。如果,做到这样,仍要抱怨说我为了得到一个Array,非要做两步操作,那真的我要搞不懂了,到底是出于什么特殊的原因,你非要得到一个底层Array呢?(事实上,在我们公司的项目,到真的总是需要得到一个纯Array用于网络传输,这是因为公司的相关制度带来的复杂性,这个在一般的Web项目中,不会出现,作为框架本身,没有必要为了照顾特殊公司的特殊规定,而去增加什么特性,所以这算不上是Yii框架的设计缺失)
另一个常见的误解,就是关于Model的批量数据操作能力。
思辨1:就我个人看来,Model应该是对数据库的一个表的一行记录的一个抽象,而不是对一张表的抽象,所以,我们并没有通过Model获得表级的操作便利。所以,不能批量插入,批量保存,这很正常,这也符合Model的定位。
思辨2:Model在设计的时候,一定也是面临了艰难的抉择,并非不能提供批量数据的能力,而是那样的话,就破坏的Model层的语义,抽象层次就出现混乱,会进一步导致更深入的误解。
思辨3:Yii框架到底如何弥补这个不方便呢,就是开放了底层的DB接口,DBCommand,DBCommandBuilder,和DBCriteria。Command相当于对一条SQL语句的封装,可以看成是一种面向对象的SQL语句表达方式,CommandBuilder就是SQL语句组装器,Criteria是查询条件的抽象,这三者构成了强大的数据库层级的语义抽象,数据库能干什么,Yii框架就能干什么,而且更加语义化,更加安全。如果你仍旧不满意,干脆可以直接传个SQL语句进去,这个口子也开了。
思辨4:有了代表单行记录的Model,和底层DB的接口,事实上,数据层的接口已经趋于完备。但是我们发现Model里面仍然是提供了几个局限性很大的批量操作,updateAll,deleteAll,就我看来,就是一种无奈,一种妥协,一种折中处理。说它有局限性,是因为这种所谓批量,只是针对单一条件的批量操作,其实本质上是相当于某个名称空间下的全局函数了,看作是“桌面快捷方式”未尝不可,因为这几个批量接口可以完全被DB层的接口的语义取代。因此,我观察到,在实际项目代码中,这几个批量操作的利用率极低。