If you want an object-oriented approach, here's what my approach has been recently.
I seperate things out into two classes,
First, a DatabaseTable class - takes a table name, a string that is that table's key. Secondly, I create a DatabaseObject class that represents a row in a DatabaseTable. The DatabaseObject has two routines setFromRow and getAsRow. SetFromRow will setup the object from an associative array of col=>value pairs, and get as row will essentially serialize the object as col=>value pairs.
The DatabaseTable uses setFromRow to manufacture DatabaseObjects when the select method is called on the table. Conversely, when it is told to update or insert data into its table, the DatabsaeTable will serialize the DatabaseObject using getAsRow.
Typically what happens is one inherits from DatabaseObject for their own particular object, defines setFromRow and getAsRow, and the DatabaseTable is told the name of the DatabaseObject to instantiate.
So what you end up writing, code wise is something like this
$dbTable = new DatabaseTable('tableName', 'uniqueid', 'InstanceType')
// dbTable manufactures an InstanceType for our use based on the select below
$dbRow = $dbTable->selectUsingId(15);
print_r($dbRow); // Dumps the InstanceTypeObject
This separates the representation of data (DatabaseObject) in my application from the management of the database tables (DatabaseTable). So my DatabaseObject can be, in C++ terminology, plain-old-data.
Of course you can go even further, as I have, by creating relationships between tables, and creating more ways to select, etc.
I should add that integrating what is essentially a procedural language (SQL) with what object-orientedness is not easy, so my method, I know, has its drawbacks and you are likely to get a lot of different answers each with their own drawbacks.