When porting a module of my site from XOOPS to Xoops², I crawled through the classes and it occured to me that some db/object accessing code is replicated throughout many classes. I wrote my own WhoswhoItem class (my module is a Who's who module for my student association), which extends XoopsObject and is the base class for all my other objects. 
I think the following code is something that could (should? 

 ) be included in the next RC/release inside the core XoopsObject class itself.
The base principle is that it uses the java-reflection-like capability of php and assumes proper naming conventions to create the concrete class instances. If this becomes a performance bottleneck, the createInstance method can be made abstract or overriden.
(forgive my typos, my own coding conventions, and so on)
 /** 
 * @abstract 
 */ 
class WhoswhoItem extends XoopsObject 
{ 
 
    function WhoswhoItem() 
    { 
        $this->XoopsObject(); 
    } 
} 
 
/** 
 * @abstract 
 */ 
class WhoswhoItemHandler extends XoopsObjectHandler  
{ 
 
    var $concreteClassName; 
 
    function WhoswhoItemHandler(&$db) 
    { 
        $this->XoopsObjectHandler($db); 
        // Of course, it assumes a correct implementation  
        // enforcing the naming conventions 
        $handlerClassName = get_class($this); 
        $this->concreteClassName = substr($handlerClassName, 0, -7); // 7 is the length of 'Handler' 
    } 
 
 
    /** 
    * Returns the table used for persistance. 
    * @abstract 
    */ 
    function getTableName() 
    { 
    } 
 
    /** 
    * Returns the complete Sql request for an Insert operation op the concrete handled subclass. 
    * @abstract 
    * @param    int        $id the id generated for this instance. 
    * @param    object    &$toStore the instance to store. 
    */ 
    function getInsertRequest($id, $toStore) 
    { 
    } 
 
    /** 
    * Returns the complete Sql request for an Update operation op the concrete handled subclass. 
    * @param    object    &$toStore the instance to store. 
    * @abstract 
    */ 
    function getUpdateRequest($toStore) 
    { 
    } 
 
    /* 
    * Returns the column name of the primary key used to 
    * retrieve instances from the table. Usuall 'id', or  'uid', .... 
    * @abstract 
    */ 
    function getPKName() 
    { 
    } 
 
 
    /** 
    * Creates an instance of the concrete handled class. 
    * @access    protected 
    */ 
    function &createInstance() 
    { 
        $className = $this->concreteClassName; 
        $value = new $className(); 
        return $value; 
    } 
 
 
    /** 
    * Creates a new instance of the concrete handled subclass.  
    * @return    bool    $isNew  Flag the object as "new"? 
    * @access    public 
    */ 
    function &create($isNew = true) 
    { 
        $value =& $this->createInstance(); 
        if ($isNew)  
        { 
            $value->setNew(); 
        } 
        return $value; 
    } 
 
 
    /* 
    * Retrieves data from DB and fills a new instance the concrete handled subclass with it. 
    * Assumes the PK id is an int. 
    * @access private 
    * @param    int $id ID  
    * @return    object instance, FALSE on fail 
    */ 
    function &get($id) 
    { 
        $sql = sprintf( "SELECT * FROM %s WHERE %s = %d ",  
        $this->db->prefix($this->getTableName()), $this->getPKName(), intval($id)); 
        if ( !$result = $this->db->query($sql) )  
        { 
            return false; 
        } 
        $numrows = $this->db->getRowsNum($result); 
        if ( $numrows == 1 )  
        { 
            $value =& $this->createInstance(); 
            $value->assignVars($this->db->fetchArray($result)); 
            return $value; 
        } 
        return false; 
    } 
 
 
    /** 
    * Stores a the concrete handled subclass.  
    * @param    object  &$toStore an instance the concrete handled subclass.  
    * @return    bool    TRUE on success 
    */ 
    function insert(&$toStore) 
    { 
        if ( get_class($toStore) != $this->concreteClassName )  
        { 
            return false; 
        } 
        if ( !$toStore->isDirty() )  
        { 
            return true; 
        } 
        if (!$toStore->cleanVars())  
        { 
            return false; 
        } 
        if ($toStore->isNew())  
        { 
            $generated_id = $this->db->genId( $this->getTableName()); 
            $sql = $this->getInsertRequest($generated_id, $toStore); 
        }  
        else  
        { 
            $sql = $this->getUpdateRequest($toStore); 
        } 
        if (!$result = $this->db->query($sql))  
        { 
            return false; 
        } 
        if (empty($generated_id))  
        { 
            $generated_id = $this->db->getInsertId(); 
        } 
        $toStore->assignVar( $this->getPKName(), $generated_id); 
        return true; 
    } 
 
    /** 
    * Deletes an instance the concrete handled subclass. 
    * @param    object  &$toDelete 
    * @return    bool    TRUE on success 
    */ 
    function delete(&$toDelete) 
    { 
        if (get_class($toDelete) != $this->concreteClassName)  
        { 
            return false; 
        } 
        $sql = sprintf("DELETE FROM %s WHERE %s = '%s'",  
            $this->db->prefix($this->getTableName()), $this->getPKName(),  
            $toDelete->getVar($this->getPKName())); 
        if (!$result = $this->db->query($sql))  
        { 
            return false; 
 
        } 
        return true; 
    } 
 
    /** 
    * Deletes all instances matching a set of conditions 
    * @param object $criteria {@link CriteriaElement}  
    * @return bool FALSE if deletion failed 
    */ 
    function deleteAll($criteria = null) 
    { 
        $sql = 'DELETE FROM '.$this->db->prefix($this->getTableName()); 
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement'))  
        { 
            $sql .= ' '.$criteria->renderWhere(); 
        } 
        if (!$result = $this->db->query($sql))  
        { 
            $this->notifyUpdate($sql, 'failed_update'); 
            return false; 
        } 
        return true; 
    } 
 
    /** 
    * Retrieves multiple instance of the concrete handled subclass. 
    * @param    object  $criteria   {@link CriteriaElement} 
    * @param    bool    $id_as_key  Use IDs as array keys? 
    *  
    * @return    array   Array of {@link XoopsGroupPerm}s  
    */ 
    function &getObjects($criteria = null, $id_as_key = false) 
    { 
        $ret = array(); 
        $limit = $start = 0; 
        $sql = 'SELECT * FROM '.$this->db->prefix($this->getTableName()); 
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement'))  
        { 
            $sql .= ' '.$criteria->renderWhere(); 
            if ( '' != $criteria->getSort() ) { 
                $sql .= ' ORDER BY '.$criteria->getSort().' '.$criteria->getOrder(); 
            } 
            $limit = $criteria->getLimit(); 
            $start = $criteria->getStart(); 
        } 
        $result = $this->db->query($sql, $limit, $start); 
        if (!$result)  
        { 
            return $ret; 
        } 
        while ($myrow = $this->db->fetchArray($result))  
        { 
            $value =& $this->createInstance(); 
            $value->assignVars($myrow); 
            if (!$id_as_key)  
            { 
                $ret[] =& $value; 
            } else  
            { 
                $ret[$myrow[$this->getPKName()]] =& $value; 
            } 
            unset($value); 
        } 
        return $ret; 
    } 
 
    /** 
    * Obtains the "db-quoted" version of the variables contents, to be able to store them directly. Just a helper method, not mandatory. 
    * @access    protected 
    */ 
    function "edCleanVars(&$object) 
    { 
        $toReturn = array(); 
        foreach ($object->cleanVars as $k => $v)  
        { 
            $toReturn[$k] = $this->db->quoteString($v); 
        } 
        return $toReturn; 
    } 
 
}  
 With this, in subclasses, you don't need the write the typical "get", "getObjects", "delete", ... methods. You only need to write:
o a Constructor
o the concrete implementation of getTableName()
o the concrete implementation of getInsertRequest()
o the concrete implementation of getUpdateRequest()
o the concrete implementation of getPKName()
All of which are quite simple and quite short methods. This makes your classes shorter to write and easier to maintain.