De database abstractielaag interface:
<?php #4

interface DB_Generic {
	public function __construct( $f_szHost, $f_szUser = '', $f_szPass = '', $f_szDb = '' ); // void
	public function saveError(); // void
	public function connected(); // bool
	public function escape( $v ); // string
	public function escapeAndQuote( $v ); // string
	public function insert_id(); // int
	public function affected_rows(); // int
	public function query( $f_szSqlQuery ); // bool / object / resource
	public function fetch($f_szSqlQuery); // array
	public function select($f_szTable, $f_szWhere = ''); // array
	public function fetch_fields($f_szSqlQuery); // array
	public function select_one($tbl, $field, $where = ''); // string / null
	public function max($tbl, $field, $where = ''); // int
	public function min($tbl, $field, $where = ''); // int
	public function count($tbl, $where = ''); // int
	public function select_by_field($tbl, $field, $where = ''); // assoc array
	public function select_fields($tbl, $fields, $where = ''); // array
	public function replace_into($tbl, $values); // bool
	public function insert($tbl, $values); // bool
	public function update($tbl, $update, $where = ''); // bool
	public function delete($tbl, $where); // bool

} // END Interface db_generic

?>

De testpagina:
<?php

// db connectie maken
require_once('../../../inc.cls.db_mysqli.php');
$db = new db_mysqli('localhost', 'user', 'pass', 'prutblog'); // extends DB_Generic

function __autoload($class) {
	require_once(dirname(__FILE__).'/inc.cls.'.strtolower($class).'.php');
}

// db connectie assignen aan ARO 'DataCenter'
ActiveRecordObject::setDbObject($db);

echo '<pre>';

$kat = AROUser::finder()->findOne('username = \'kat\'');
$kat->bff; // jaap
echo 'User katrien: ';
print_r($kat);

$jaap = AROUser::finder()->byPk(1);
$jaap->bff; // no record found, so empty record stored
echo "\n".'User jaap: ';
print_r($jaap);

$posts = $jaap->posts;
echo "\n".'Jaap\'s posts: ';
print_r($posts);
// OR
$posts = AROPost::finder()->findMany('user_id = '.$jaap->id);
echo "\n".'Nogmaals: ';
print_r($posts);

echo "\n";

echo "\n".'Post [3] met childs: ';
$post3 = AROPost::finder()->byPK(3);
$post3->creator->posts;
print_r($post3);

// Een slecht voorbeeldje van saveAsNew():
$post3->title = 'alleen een andere titel dan';
var_dump($np=$post3->saveAsNew()); // int(7)
AROPost::finder()->byPk($np); // het object
// je gaat natuurlijk geen post letterlijk kopieren, maar je snapt dat het kan

?>

Class AROUser
<?php

class AROUser extends ActiveRecordObject {

	protected static $_table = 'users';
	protected static $_columns = array(
		'username',
	//	'password', # there really is no use to update this, so don't list it. It will be fetched though (see * in getQuery())
		'name',
		'email',
		'bff_friend_id',
	);
	protected static $_pk = 'id';
	protected static $_relations = array(
		'posts' => array( self::HAS_MANY, 'AROPost', 'user_id'/*, 'id'*/ ), # `id` is default
		'bff' => array( self::HAS_ONE, 'AROUser', 'bff_friend_id' ),
	);

	static public function finder( $class = __CLASS__ ) {
		return parent::finder($class);
	}

	public function getQuery( $clause ) {
		$szQuery = 'SELECT * FROM users WHERE 1';
		if ( $clause ) {
			$szQuery .= ' AND '.$clause;
		}
		return $szQuery.';';
	}

	public function updatePassword( $pwd ) {
		return $this->getDbObject()->update(
			$this->getStaticChildValue('table'), # table
			array('password' => md5($this->id.':'.$pwd)), # updates
			$this->getStaticChildValue('pk').' = '.$this->id # WHERE clause
		);
	}


} // END Class AROUser

?>

Class AROPost
<?php

class MyDateTime {
	private $utc;
	function __construct($utc) {
		$this->utc = $utc;
	}
	function __tostring() {
		return (string)$this->utc; # __tostring must always return database format
	}
	function text() {
		return $this->date().' '.$this->time();
	}
	function date() {
		return date('Y-m-d', $this->utc);
	}
	function time() {
		return date('H:i:s', $this->utc);
	}
}

class AROPost extends ActiveRecordObject {

	protected static $_table = 'posts';
	protected static $_columns = array(
		'parent_post_id', # FK (NULL)
		'user_id', # FK
		'title',
		'content',
		'created', # int
	);
	protected static $_pk = 'id';
	protected static $_relations = array(
		'creator' => array( self::HAS_ONE, 'AROUser', 'user_id'/*, 'id'*/ ), # `id` is default
		'replies' => array( self::HAS_MANY, 'AROPost', 'parent_post_id', 'id' ),
	);

	static public function finder( $class = __CLASS__ ) {
		return parent::finder($class);
	}

	public function fill($data) {
		parent::fill($data);
		$this->created = new MyDateTime($this->created);
	}

	public function getQuery( $clause ) {
		$szQuery = 'SELECT * FROM posts WHERE 1';
		if ( $clause ) {
			$szQuery .= ' AND '.$clause;
		}
		return $szQuery.';';
	}


} // END Class AROPost

?>