Q:

Work with database in classes

I´m wondering how to work with database in classes. For example how to write queries for easy future edit and by OOP rules.
First example:
    class User {

    public function select($query) {
        //work with data
        return $data;
    }

    public function insert($query) {
        //work with data
    }
}

In this example user (me) add queries for each method. For me, big disadvantage is that I must remember correct form of my query. This example is easy to understand, but in case I will work with more complex queries, it would hard to write correct form of query.
Next example:
class User {

    const select = "SELECT * FROM user WHERE ID = ?";
    const insert = "INSERT INTO user VALUES (?)";

    public function select($id) {
        //work with data
        return $data;
    }

    public function insert($id) {
        //work with data
    }
}

I defined each query as contstant. This form of class is very handy but on the other hand if I want to get ID of user I can't, because I would know name of ID field in the database. This problem I solve in third example
Third example:
class User {

    private $table, $idField;

    public function setDatabaseInformation($table, $idField) {
        $this->table = $table;
        $this->idField = $idField;
    }

    public function select($id) {
        //work with data
        //query as SELECT * FROM $this->table WHERE $this->idField = ?
        return $data;
    }

    public function insert($id) {
        //query as INSERT INTO $this->table VALUES (?)";
        //work with data
    }

}

Personaly I think, this example is the best, because there I have everything what I want and I can't rememeber forms of queries. On the other hand, this example is a bit longer, very universal and I don't know it is correct by OOP rules.
My questions are: Is there any other options how to write queries in database? Is the last example correct by OOP rules? Which way do you use?
Thanks for suggestions.

A:

Abstract the whole thing inside the class! You want to write code which looks like this in the end:
$database    = new PDO(...); // or whatever
$userStorage = new UserStorage($database);

$user  = $userStorage->getById(42);
$users = $userStorage->getByName('Joe');

class UserStorage {

    protected $db;

    public function __construct(PDO $db) {
        $this->db = $db;
    }

    public function getById($id) {
        $stmt = $this->db->prepare('SELECT ... WHERE id = ?');
        $stmt->execute([$id]);
        ...
        return $user;
    }

    ...

}

You only want to write each logical query once in one specific, authoritative place. For each possible logical "action", create a method (one method to get users by id, one to get them by name, etc.). Each method can be as complex or simple as necessary internally, but it is the one place where you write the specific query to get the specific data. Lastly: dependency inject your database connection.

