So I'm trying to adopt good object oriented programming techniques with PHP. Most (read all) of my projects involve a MySQL database. My immediate problem deals with the users model I need to develop.
My current project has Agents and Leads. Both Agents and Leads are Users with much of the same information. So, obviously, I want a class Agents and a class Leads to extend a common class Users. Now, my question is as follows:
How should the SQL best be handled for loading these objects? I don't want to execute multiple SQL statements when I instantiate an Agent or a Lead. However, logic tells me that when the Users constructor is fired, it should execute a SQL statement to load the common information between Agents and Leads (username, password, email, contact information, etc). Logic also tells me that when the Agents or Leads constructor is fired, I want to execute SQL to load the data unique to the Agents or Leads class....But, again, logic also tells me that it's a bad idea to execute 2 SQL statements every time I need an Agent or Lead (as there may be thousands of each).
I've tried searching for examples of how this is generally handled with no success...Perhaps I'm just searching for the wrong thing?
解决方案
You basically have three approaches to this problem (one of which I'll eliminate immediately):
One table per class (this is the one I'll eliminate);
A record type with optional columns; and
A record type with a child table depending on type that you join to.
For simplicity I generally recommend (2). So once you have your table:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
type VARCHAR(10),
name VARCHAR(100)
);
where type can be 'AGENT' or 'LEAD' (for example). Alternatively you can use one character type codes. You can then start to fill in the blanks with the object model:
You have a User parent class;
You have two child classes: Lead and Agent;
Those children have a fixed type.
and it should fall into place quite easily.
As for how to load in one statement, I would use some kind of factory. Assuming these barebones classes:
class User {
private $name;
private $type;
protected __construct($query) {
$this->type = $query['type'];
$this->name = $query['name'];
}
...
}
class Agent {
private $agency;
public __construct($query) {
parent::constructor($query);
$this->agency = $query['agency'];
}
...
}
class Lead {
public __consruct($query) {
parent::constructor($query);
}
...
}
a factory could look like this:
public function loadUserById($id) {
$id = mysql_real_escape_string($id); // just in case
$sql = "SELECT * FROM user WHERE id = $id";
$query = mysql_query($sql);
if (!query) {
die("Error executing $sql - " . mysql_error());
}
if ($query['type'] == 'AGENT') {
return new Agent($query);
} else if ($query['type'] == 'LEAD') {
return new Lead($query);
} else {
die("Unknown user type '$query[type]'");
}
}
Alternatively, you could have the factory method be a static method on, say, the User class and/or use a lookup table for the types to classes.
Perhaps polluting the classes with the query result resource like that is a questionable design in the strictest OO sense, but it's simple and it works.