I was thinking today about database APIs when inspiration struck. I ended up hacking out the following class, which I think demonstrates a rather interesting approach to interfacing with a database (interesting enough at least to post here).
class DBQuery implements IteratorDBQuery isn't your typical database access class. In fact, I would suggest it's slightly evil since it distorts traditional PHP syntax by abusing taking advantage of three specific PHP features.
{
protected $_db;
protected $_query;
protected $_result;
protected $_index;
protected $_num_rows;
public function __construct($host, $dbname, $username,
$password) {
$this->_db = new PDO("mysql:dbname=$dbname;host=$host",
$username, $password);
}
public function __get($query) {
$this->_query = $query;
$this->_result = $this->_db->query($query);
return $this->_num_rows = $this->_result->rowCount();
}
public function quote($value) {
return PDO::quote($value);
}
public function __call($query, $values) {
$this->_query = $query;
$this->_result = $this->_db->prepare($this->_query);
$this->_result->execute($values[0]);
return $this->_num_rows = $this->_result->rowCount();
}
public function clear() {
$this->_index = 0;
$this->_num_rows = 0;
$this->_query = '';
$this->_result->closeCursor();
}
public function rewind() {
$this->_index = 0;
}
public function current() {
return $this->_result->fetch(PDO::FETCH_ASSOC,
PDO::FETCH_ORI_ABS, $this->_index);
}
public function key() {
return $this->_index;
}
public function next() {
$this->_index++;
}
public function valid() {
return ($this->_index < $this->_num_rows);
}
public function __toString() {
return $this->_query;
}
}
- PHP allows special characters in an identifier if the string is quoted and is enclosed by {}. So, $myValue and
${"my value"} are both equally valid variable identifiers. - The magic overloading methods allow you handle undefined properties and methods in your class. Specifically, I've made use of __get() and __call().
- A class that implements the Iterator interface can be traversed using a foreach loop.
// connect to the databaseDon't try this at home, though, my friends. Just because you can write code like this doesn't mean you should.
$dbq = new DBQuery("localhost", "test", "dbuser",
"dbpassword");
// query the database if the user is authorized
$username = "administrator";
$password = sha1("password");
if (!$dbq->{"SELECT * FROM admin_user WHERE username=? " .
"AND password=?"}(array($username, $password))) {
die("Unauthorized.");
}
// query the database and display some records
$dbq->{"SELECT id, first_name, last_name FROM employee"};
foreach ($dbq as $result) {
print_r($result);
}
// casting the object as a string yields the query string
echo "Query: $dbq";
Amazing concept, but I'm afraid if I ever see ANY of this code in production in the future I will be forced to strangle you... Consider yourself warned :)
ReplyDeleteYou could make it even hackier by using func_get_args() in __call so the usage would turn out as
ReplyDelete$dbq->{"SELECT * FROM admin_user WHERE username=? AND password=?"}($username, $password)
Yep this is a pretty cool idea. Wouldn't go as far as Commenter #1, but I think it may be a good idea to not bend the rules this much ;)
ReplyDeleteps: why do I have to log in to comment? I don't want to - please make it possible to comment by just leaving your name =)
this looks pretty neat.
ReplyDeletebut I don't understand why you shouldn't use something like this ?
what rules it bends ?