但这些属性是可用的;它们保存在 $fieldvalues 数组内。并且其上的代码也能正常工作。为了提供对域属性的无缝访问以便上述引用的语法能正常工作,ActiveRecord 实现了奇妙的 __get 方法。代码底部的第二个声明显示了 Customer 对象是如何从 findById 方法被检索到的,以及 email 属性是如何被访问的。Customer 没有 email 属性,但是由于定义了 __get 方法,PHP 调用了 __get 方法,并以一个参数传递了所请求的属性名。之后,__get 方法只需简单地从 $fieldvalues 数组拉出属性值。 注意: 生产代码可以处理对数组内不存在的属性的请求。 动态 finder 方法和 __callStatic 活动记录设计模式实现内经常提供的一个很棒的特性是动态 finder 方法。没有动态方法,域类的代码编写将必须考虑到类的每个数据库查询用户可能会要求检索域的一个或多个实例(并随后编写一个类似于 findById 的方法)。 我们来重点看看 清单 5 底部的最后一个声明:它运行一个名为 findByLastname 的方法。但该方法不具备任何实现。此方法可能不会存在,但是由于 Customer 类的父类具有 PHP V5.3 的新 __callStatic 方法的一个实现,所以不仅不会抛出任何错误,而且 findByLastname 调用还会实际执行并会做一些有价值的事情。 __callStatic 方法接受两个参数:被调用的方法名以及一个参数数组。当调用 findByLastname 时,PHP 看到此名称不存在并会运行 ActiveRecord 的 __callStatic 方法,在第一个参数内传递 findByLastname,第二个参数内传递 Denoncourt 作为一个数组。 __callStatic 的 ActiveRecord 实现去掉 findBy 前缀后跟的字符串并将其用作 SQL where 子句内的字段名。 __callStatic 方法然后会使用 Denoncourt 实参作为对比值。有了动态调用,还可以使用如下这行代码: Customer::findByEmail('dondenoncourt@gmail.com'); 注意您还可以增进 __callStatic 方法来支持操作符,如下所示: Sales::findAllByQtyGreaterThan(100); 显然,活动记录的生产实现将远比此更为复杂并会处理除 findBy 外的一些方法前缀。这些方法前缀可能会包含 findAllBy 来返回行的数组,使用 countBy 来返回与条件相匹配的那些行。 注意: 现在已经出现了一些利用 PHP V5.3 新特性的活动记录框架 — Dirivante 和 php.activerecord —(参考资料)。 结束语 成长于 20 世纪 70 年代的我们经常会听到一个口号“不要给我非静态的”。但是对于 PHP V5.3,我很高兴拥有很多静态的东西 — 比如继承树内的静态属性和方法。PHP V5.3 的 LSB 功能让您可以使用需要静态属性和方法的设计模式。PHP 还提供了 get_called_class 供您大量使用,因为您要实现的设计模式常常会需要衍生类的类名。有了 PHP V5.3 的奇妙 __callStatic 函数,更多的创造性在等待着您。 |