活动记录模式则可用来在域类内包装关系数据库持久性方法。一个活动记录的每个实例都关系到数据库内的特定行。这个类包含了要插入、删除和更新数据库内的一行或多个行的方法。活动记录设计模式是由 Martin Fowler 在 Patterns of Enterprise Application Architecture 内定义的,并因在 Ruby on Rails 内的使用而日益流行。
<?php
class ConnPool {
private static $onlyOne;
private static $count = 0;
private function __construct() {
// real-world db conn stuff here...
}
public static function getInstance() {
if (!is_object(self::$onlyOne)) {
$klass = __CLASS__;
self::$onlyOne = new $klass();
self::$count++;
}
return self::$onlyOne;
}
public static function getInstanceCount() {return self::$count;}
}
<?php
class ConnPool {
private static $onlyOne;
protected static function getClass() {
return __CLASS__;
}
public function get_instance() {
if (!is_object(self::$onlyOne)) {
$klass = static::getClass();
self::$onlyOne = new $klass();
}
return self::$onlyOne;
}
}
<?php
abstract class ActiveRecord {
protected static $table;
protected $fieldvalues;
public $select; // used for illustration only
static function findById($id) {
$query = "select * from "
.static::$table
." where id=$id";
return self::createDomain($query);
}
function __get($fieldname) {
return $this->fieldvalues[$fieldname];
}
static function __callStatic($method, $args) {
$field = preg_replace('/^findBy(\w*)$/', '${1}', $method);
$query = "select * from "
.static::$table
." where $field='$args[0]'";
return self::createDomain($query);
}
// TODO: code a __set method
private static function createDomain($query) {
$klass = get_called_class();
$domain = new $klass();
$domain->fieldvalues = array();
$domain->select = $query;
foreach($klass::$fields as $field => $type) {
$domain->fieldvalues[$field] = 'TODO: set from sql result';
}
return $domain;
}
// TODO: code static create, update, delete methods
}
class Customer extends ActiveRecord {
protected static $table = 'custdb';
protected static $fields = array(
'id' => 'int',
'email' => 'varchar',
'lastname' => 'varchar'
);
}
class Sales extends ActiveRecord {
protected static $table = 'salesdb';
protected static $fields = array(
'id' => 'int',
'item' => 'varchar',
'qty' => 'int'
);
}
assert ("select * from custdb where id=123" ==
Customer::findById(123)->select);
assert ("TODO: set from sql result" ==
Customer::findById(123)->email);
assert ("select * from salesdb where id=321" ==
Sales::findById(321)->select);
assert ("select * from custdb where Lastname='Denoncourt'" ==
Customer::findByLastname('Denoncourt')->select);
?>
ActiveRecord 类使用 abstract 修饰符来确保代码不会实例化一个 ActiveRecord 对象。如果用 new ActiveRecord(); 尝试创建一个 ActiveRecord,将会收到一个错误,称 “PHP Fatal error: Cannot instantiate abstract class ActiveRecord”。这是一件好事,因为在没有子类时,ActiveRecord 类不会做任何有价值的事情。