再谈Zend_Db_Select
作者:老王
前些天,我写了一篇题为“在PHP中如何让创建对象的过程变得更可读”的文章,描述了如何使用连贯接口让对象的创建更具可读性,很多网友提出不同的看法,比如说有的认为用数组更好,还有的则直接搬出我以前对Zend_Db_Select的批评,不错,以前我在不同的场合都多次强调过Zend_Db_Select是典型的伪OO实现,现在我承认我的看法有些过于偏激,但是我仍然不认为Zend_Db_Select是一个好设计。
先看看Zend_Db_Select最一般的用法:
$select = $db->select()->from( ...specify table and columns... )->where( ...specify search criteria... )->order( ...specify sorting criteria... );
这确实是一种连贯接口的用法。那么我一会说这样好,一会又说这样不好,是不是前后矛盾呢?不矛盾!首先,我们想想为啥我们要使用连贯接口,这是因为我们要赋予代码DSL那样的可读性,但是不要忘记了,SQL语句本身就是一种很好的描述语言了,在它上面再进行一次Zend_Db_Select封装意义不大,当然,有人会说Zend_Db_Select实现了一个数据抽象层,一套代码可以在不同的数据库环境下使用,但这又牵扯出另一个问题,数据抽象层真的那么NB么?反正我觉得在PHP中的数据抽象层是一个供程序员意淫的层(参考链接)!
再者,我们看看Zend_Db_Select创造的criteria里都用的是些什么东西,有表,有用字段,也就是说,Zend_Db_Select本身和数据库强耦合。这就又是问题了,criteria应该是描述对象,属性如何如何(参考Hibernate的HQL),而不是表,字段如何如何。如果放在分层体系里(表现层,应用层,领域层,持久层),我们需要的criteria应该位于领域层才对,只有领域层才需要DSL(Domain Specific language),而从Zend_Db_Select的实现看,它明显不属于所谓领域层,而应该属于持久层,那么它就算不上DSL,至少不是有意义的DSL。
末了,再说一下网友提出的几个问题:
呵呵,记得老王曾经强烈鄙视过ZF中的method chain,如果去掉上面的return $this;
那么老王所说的“更可读”只不过是方 法名的变化而已,set到with的转变,也只是让new的时候好看一点,如果放到程序中间,突然冒出一个$person->withName ("xxx");绝对不如$person->setName("xxx")易懂...
确实,从表面上看,这无非是方法名字的简单变化而已,但是恰恰是名字的改变,让我们看到了概念的力量,DSL也正是由这种力量驱动的。
至于上面说的“突然冒出一个$person->withName ("xxx");绝对不如$person->setName("xxx")易懂”,那是当然,因为既然是当DSL使用的,就肯定是作为一个整体存在的,DSL调用,是有上下文的说道的,不可能单独使用其中的一部分,好像我们使用Zend_Db_Select的时候,单独使用$select->where()也是没有意义的一样。
搜索更多相关主题的帖子:
Zend_Db_Select