Php – Reference counting in PHP


I'd like to implement database caching functionality in PHP based on reference counts. For example, code to access the record in table foo with an ID of 1 might look like:

$fooRecord = $fooTable->getRecord(1);

The first time this is called, $fooTable fetches the appropriate record from the database, stores it in an internal cache, and returns it. Any subsequent calls to getRecord(1) will return another reference to the same object in memory. $fooRecord signals $fooTable when it destructs, and if there are no remaining references, it stores any changes back to the database and removes it from the cache.

The problem is that PHP's memory management abstracts away the details about reference counts. I've searched PECL and Google for an extension to do so, but found no results. So question #1 is: does such an extension exist?

In an alternative approach, $fooTable returns a super-sneaky fake object. It pretends to be the record by forwarding __call(), __set(), and __get(), and its constructor and destructor provide the appropriate hooks for reference counting purposes. Tests, works great, except that it breaks type-hinting. All my methods that were expecting a FooRecord object now get a Sneaky object, or maybe a FooSneaky if I feel like creating an empty subclass of Sneaky for every one of my tables, which I do not. Also, I'm afraid it will confuse maintenance programmers (such as myself).

Question #2: Is there another approach I've missed?

Best Solution

For php5, just make use of the destructor in the record class.

class Table {
    /* [...] */
    protected $record_cache = array();
    public function getRecord($id) {
        if(isset($this->record_cache[$id]) return $this->record_cache[$id];

        $r = $db->getRecord($id);
        if($r instanceof Record) {
            $this->record_cache[$id] = $r;
        return $r;

    public function _unregister($id) {

class Record {
    /* [...] */
    function __destruct() {

If you don't want to have a public method for this in Table, you could probably use some callback trick or some other clever hack :)