First of all, your Question classes should have nothing to do with the database in the first place. They should purely be dumb domain objects, which just hold data and maybe enforce a bit of data validation on it:
class Question {
protected $title;
protected $body;
...
public function setTitle($title) {
if (strlen($title) == 0) {
throw new InvalidArgumentException(...);
}
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
...
}
Depending on your requirements, you make some of these attributes required by requiring them in the constructor. By doing that you ensure that if you have an instance of Question, it has at least the minimal attributes that make it a valid question:
public function __construct($title) {
$this->setTitle($title);
}
Again, notice that this object has absolutely no concept of what a database is. That's the responsibility of some other class, which has access to a database connector and can read from Question objects to store them in the database and create new Question objects from database data:
class QuestionStore {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
public function getQuestion(...) {
$data = $this->db->query('SELECT ...');
$question = new Question($data['title']);
$question->setBody($data['body']);
return $question;
}
}
(You can debate about separating those responsibilities further into factories etc, but you get the basic idea.)
How to handle ids then becomes pretty trivial. Either you just make the id one of the non-required attributes of your Question class, so some Question instances have ids and others don't while they haven't yet been saved in the database. Or, if it's somewhat important to your code to distinguish between those two types of questions more easily, make a subtype out of it:
class StoredQuestion extends Question {
protected $id;
public function __construct($id, $title) {
$this->setId($id);
parent::__construct($title);
}
...
}
questions?