Bean Patterns in Typed and Untyped Languages

by | February 6th, 2009

I’ll be looking at C# and PHP in this post; C# is a strongly typed programming language and PHP is an untyped language.

Supposedly, a key benefit of a strongly typed programming language is that it forces programmers to think about the types of the pieces of data they’re working with in a way that eliminates many errors.  This leads to programming patterns that resemble Java’s beans or enterprise beans (see also Hibernate).  It can take considerable set up time to generate the most basic of classes to describe a database table or other data structure, but once done, these classes can be quite powerful.

First, let’s look at a simple database table that holds user and login information for authentication:

create table Users (
    userid int auto_increment,
    username varchar(32),
    password varchar(64),
    primary key(userid)
);

The examples that follow will use this table.

C# Patterns

Here’s a sample bean-like pattern in C# to work with this table:

public class User {
	protected int _userid;
	protected string _username;
	protected string _password;
	protected boolean isDirty;
	// properties
	public int userid {
		get { return _userid; }
		set { _userid = value; isDirty = true; }
	}
	public char[] username {
		get { return _username; }
		set { _username = value; isDirty = true; }
	}
	public char[] password {
		get { return _password; }
		set { _password = value; isDirty = true; }
	}
	// constructor
	public User() {
		_userid = 0;
		_username = "Guest";
		_password = "";
		isDirty = false;
	}
	// Helper methods
	public void LoadFromDictionary(Dictionary<string,string> d) {
		if (d) {
			this.userid = (int)d['userid'];
			this.username = d['username'];
			this.password = d['password'];
			this.isDirty = false;
		}
	}
	// "Getter" methods
	public static User GetByUserId(int id) {
		User u = new User();
		Dictionary<string, string> user_record = Database::Query("SELECT * FROM Users WHERE userid=" + id);
		u.LoadFromDictionary(user_record);
		return u;
	}
	public static User GetByUsername(string username) {
		User u = new User();
		Dictionary<string, string> user_record = Database::Query("SELECT * FROM Users WHERE userid=" + id);
		u.LoadFromDictionary(user_record);
		return u;
	}
	// Update to Database
	// stores if userid is non-zero
	// creates (auto_create!) if userid zero
	public void StoreOrCreate() {
		if (!this.isDirty) {
			return;
		}
		SqlStatement statement = Database::PrepareQuery("REPLACE INTO Users VALUES (?,?,?)");
		statement.add(this.userid);
		statement.add(this.username);
		statement.add(this..password);
		Database::Execute(statement);
		this.isDirty = false;
	}

        // discard this object (so it won't be stored to the DB)
        public void Discard() {
            this.isDirty = false;
        }

	// Destructor
	~User() {
		this.StoreOrCreate();
	}
};
.

The programming patterns for using this class are powerful and flexible:

.

Create a new user

User u = new User();
u.username = "mschwartz";
u.password = "c#rox";
u.StoreOrCreate();
.

Process a set of users’ records

User u = new User();
SqlResultSet r = Database::Query("SELECT * FROM Users");
while (Dictionary<string,string> d = r.NextRow()) {
    u.LoadFromDictionary(d);
    ProcessUserRecord(u);
}
.

Update a user’s password

User u = User.GetByUsername("mschwartz");
u.password = "mynewpassword";
u.StoreOrCreate();

The “hard” work was in setting up the User class, but using it in practice can be quite expressive.

.

PHP Bean Patterns

PHP has classes but not properties, though “get” and “set” methods can be implemented to achieve a similar construct.   Bean patterns can equally be implemented in PHP:

class User {
	protected $userid;
	protected $username;
	protected $password;
	protected $isDirty;
	// properties (get/set methods)
	function get_userid() { return $this->userid; }
	function set_userid($userid) { $this->userid = $userid; $this->isDirty = true; }
	function get_username() { return $this->username; }
	function set_username($username) { $this->username = $username; $this->isDirty = true; }
	function get_password() { return $this->password; }
	function set_password($password) { $this->password = $password; $this->isDirty = true; }
	// Constructor
	function User() {
		$this->userid = 0;
		$this->username = "Guest";
		$this->password = "";
		$this->isDirty = false;
	}
	// Helper methods
	function LoadFromObject($obj) {
		if ($obj) {
			$this->userid = $obj->userid;
			$this->username = $obj->username;
			$this->password = $obj->password;
			$this->isDirty = true;
		}
	}
	// "Getter" methods
	public static function GetByUserId($userid) {
		$u = new User();
		$rs = Database::Query("SELECT * FROM Users WHERE userid=$userid");
		$obj = $rs->fetch_object();
		$u->LoadFromObject($obj);
	}
	public static function GetByUsername($username) {
		$u = new User();
		$rs = Database::Query("SELECT * FROM Users WHERE username='" . addslashes($username) . "'");
		$obj = $rs->fetch_object();
		$u->LoadFromObject($obj);
	}
	// Update to Database
	public function StoreOrCreate() {
		if (!$this->isDirty()) {
			return;
		}
		Database::Query("REPLACE INTO Users VALUES ($this->userid, '" . addslashes($this->username) . "', '" .addslashes($this->password) . "')");
		$this->isDirty = false;
	}
	// destructor
	function __destruct() {
		$this->StoreOrCreate();
	}
};
.

The programming patterns for using this class are as powerful and flexible as with the C# version:

Create a new user

$u = new User();
$u->username = "mschwartz";
$u->password = "c#rox";
$u->StoreOrCreate();

Process a set of users’ records

$u = new User();
$r = Database::Query("SELECT * FROM Users");
while ($obj = $r->fetch_object()) {
        $u->LoadFromDictionary($obj);
        ProcessUserRecord($u);
}

Update a user’s password:

$u = User::GetByUsername("mschwartz");
$u->password = "mynewpassword";
$u->StoreOrCreate();

.

This merely proves that the bean pattern can be implemented in PHP as well.

The BETTER PHP Pattern

PHP is not typed, so we don’t need to use anything like the bean pattern.  The built-in typeless standard array in PHP is all we need, and its use can be far more elgant in implementation and practice:

class User {
    static function Get($example, $db = null) {
        $where = array();
        foreach ($example as $key => $value) {
            $where[] = "$key=$value";
        }
        if (!isset($db)) {
            $db = new Database();
        }
        $rs = $db->Query("SELECT * FROM Users WHERE " . join(' AND ', $where);
        return $rs->fetch_assoc();
    }
    static function Put($user, $db) {
        if (!isset($user)) {
            return;
        }
        if (!isset($db)) {
            $db = new Database();
        }
        $db->Query("REPLACE INTO Users VALUES (" . $user['userid'] . ", '" . addslashes($user->username) . "', '" .addslashes($user->password) . "')");
    }
    static function New() {
        return array('userid' => 0, 'username' => 'Guest', 'password' => '');
    }
};
.

This simple class provides two static methods, Get, Put, and New that are all we need. The Get function illustrates a concept called “query by example.”  How does it work?  Examples of query by example should make it clear!

$user = User::Get(array('userid' => 1)); // get user with userid = 1
$user = User::Get(array('username' => 'mschwartz')); // get my user record
$user = User::Get(array('userid' => 1, 'username' => 'mschwartz')); // my userid must be 1 or it fails!

Let’s look at the example use cases from the bean patterns.

Create a new user

$user = User::New();
$user['username'] = 'mschwartz';
$user['password'] = 'phpr0x!';
User::Put($user);

Process a set of records

$rs = $db->Query("SELECT * FROM Users");
while ($user = $rs->fetch_assoc()) {  // no need for LoadFromObject() type method
    ProcessUser($user);
}

Change a user’s password

$user = User::Get(array('username' => 'mschwartz'));
$user['password'] = 'mynewpassword';
User::Put($user);

As you can see, Get and Put work nicely together.  There is a bit more to this pattern – the $db handle is optionally passed in to both routines. Get can be called in a loop (for example) without requiring it to create a new database handle each time.  Put likewise can be called in a loop without the new handle overhead each time, but also the caller can start a transaction on the handle before calling Put and rollback on any database error.  What’s not shown is the Database class, which will throw an Exception (with the query and error text) upon error.  Let’s see how this might be used in practice:

$db = new Database();
$db->BeginTransaction();
try {
    User::Put($user, $db);
    UserExtra::Put($user_extra_information, $db);
    $db->Commit();
}
catch (Exception $e) {
    $db->Rollback();
    echo $e->getMessage(); // something like "you have an error in your SQL syntax"
}