Persistable Classes - By PHP Expert


The following code snippet implements the above-mentioned persistable class in less than 50 lines of PHP code by using property overloading. The term persistable means that the class can represent an element from a data structure while keeping it synchronized with an underlying storage system. This rather scientific explanation means in practice that other code can use the class to select a row from a database table. Directly accessing the class properties during runtime manipulates the elements of this row (by both reading and writing). When the script ends, PHP will take care of writing the updated row data back to the database.

Look through the code now to get a first impression of what is happening. After the code is a walk-through of the relevant parts of the code. At the end, you'll have a solid understanding of property overloading.

<?php
// Load the PEAR DB package
require_once "DB.php";

class Persistable {

private $data = array();
private $table = "users";

public function __construct($user) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");

$query = "SELECT id, name, email, country FROM " .
$this->table . " WHERE name = ?";
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}

public function __get($member) {
if (isset($this->data[$member])) {
return $this->data[$member];
}
}

public function __set($member, $value) {
// The ID of the dataset is read-only
if ($member == "id") {
return;
}

if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}

public function __destruct() {
$query = "UPDATE " . $this->table . " SET name = ?,
email = ?, country = ? WHERE id = ?";
$this->dbh->query($query, $this->name, $this->email,
$this->country, $this->id);
}
}

$class = new Persistable("Martin Jansen");

$class->name = "John Doe";
$class->country = "United States";
$class->email = "john@example.com";
?>

The first item that you may have stumbled across is the method __construct(). This is the new constructor method in PHP 5. In the good old days of PHP 4, constructor names matched their classes. That changed with PHP 5. You don't need to know much about the constructor method except that it is called to create an instance of the class; that it takes one argument here; and that it executes a database query based on this argument. The constructor assigns the return value of this query to the class property $data.

Next, the code defines two special methods called __get() and __set(). They are already familiar to you from the introduction: __get() is called when reading the value of an undefined property, and __set() is called when changing the same property's value.

This means that whenever someone reads or writes an undefined property from the persistable class, the special methods manipulate the information in the $data property array instead of changing the class properties directly. (Remember: $data contains the row from the database!)

The last class method is the counterpart of __construct(). It is the destructor method __destruct(). PHP calls destructors during the "script shutdown phase," which is typically right before the execution of the PHP script finishes. The destructor writes the information from the $data property back into the database. This is what the term synchronization (see above) stands for.

You have surely noticed that the above code uses PEAR's database abstraction layer package. This is solely syntactic sugar--the script of course works the same when using other ways to speak to the database.

If you look closely, you'll notice that the persistable class is limited in its current form. It works only with exactly one database table and thus does not allow the use of more complex data models that employ LEFT JOINs or other fancy database features. The sky's the limit, though; using property overloading in no way limits the flexibility of the database model. With just a bit more code, you can easily use sophisticated features of the database inside the persistable class.

Another little issue is the fact that there is virtually no error handling when the query in the destructor fails. It is in the nature of destructors that it often turns out to be impossible to display an error message in this case, because constructing the HTML markup has usually finished before PHP calls the destructor.

In order to solve this problem, you might rename __destruct() to something such as saveData() and execute the method manually somewhere in the calling script. This doesn't change anything in the concept of persistable classes; it just requires a bit more typing when writing code that uses the class. Alternatively, you can use the error_log() function in the destructor to log the message that belongs to the error in the systemwide error log file.
That's all the code necessary for the use case of property overloading. Next up is method overloading.

No comments
Tips for optimizing php code by PHP Expert Important SERVER Variables in PHP - By PHP Expert Improved Error Messages in PHP 5 - By PHP Expert New Object Oriented Features - By PHP Expert New Object Oriented Features - By PHP Expert New Object Oriented Features - By PHP Expert New Object Oriented Features - By PHP Expert New Object Oriented Features - By PHP Expert New Object Oriented Features - By PHP Expert New Object Oriented Features - By PHP Expert Object Overloading in PHP 5 Persistable Classes - By PHP Expert Dynamic Getter/Setter Methods - By PHP Expert New Functions in PHP 5 New Directives - By PHP Expert Exception Handling - By PHP Expert Password Encryption in PHP - By PHP Expert Output Buffering in PHP - By PHP Expert Page Excerpts Using CURL - By PHP Expert Quick and Easy Google Site Search - By PHP Expert Always Be Notified When Google Crawls Your Site - By PHP Expert How to POST Form Data using CURL - By PHP Expert Cryptography for web developers - By PHP Expert Dynamically Loading JavaScript Files - by PHP Expert What is Web 2.0 - By PHP Expert