Back to the blog
Recent Posts
-
Aug 31
A bit of icon work
-
Jun 24
Your mobile OS can't really multitask...
-
Apr 27
Thoughts on Android and the HTC Dream
-
Feb 26
Announcing Twitterscribe: archive your tweets
-
Jan 01
Adventures in PHP interfaces
-
Oct 17
How do you mockup websites?
Most Popular Posts
-
Why you should be using a framework
-
Dynamic methods in PHP
-
Rewriting URLs with Apache's mod_rewrite and PHP
-
Five easy things that make you a better web developer
About the Blog

I'm a web application developer in Melbourne, Australia. If you find anything useful, leave me a comment, and if you need web design, development, or accessibility and usability consulting, contact me! Cheers.
Twitter: joshsharp
Adventures in PHP interfaces
Thursday 01 Jan, 2009 10:58 PM
So recently I've been having a play with Python. I like it a lot, and it's started to affect how I code in PHP — all of my freelance work still uses PHP, so it's still my 'primary' coding language. However, this means that all the little things I can do faster in Python come back to haunt me in PHP. It was bound to happen. Unfortunately, though, I can't just switch all my work to Python (and it has a number of shortcomings that make it harder to support, anyway) so to resolve this I've been attempting to replicate, in my PHP framework Rex, some of the things which in Python make my life easier.
The first of these is the syntactic sugar of SQLAlchemy's (and AppEngine's, Django's, and others) data selection syntax. With some nifty method chaining, SQL queries can be abstracted to such pretty code (yes, in PHP) as $user = User->all()->filter('Admin = 0')->order('FirstName','ASC')->go()->get(0);. I might follow up this post with another explaining how to achieve this method chaining, and it's really quite easy, but in the meantime I want to draw your attention to something else.
Scrutinise the line of code above for a moment. The very last function call is get(0), which will return the first index in the results array. Hold on, an array? That's right. Usually to get an array of rows back, there is a two-stage process in accessing the first index:
$results = $User->someMethodReturningUsers(); $user = $results[0];
It always really bothered me that you couldn't just chain an array index to the end, like $user = $User->someMethodReturningUsers()[0]; which is perfectly acceptable in a lot of other dynamic languages. But, aha! That's what we're about to solve.
ArrayAccess, Countable, and Iterator interfaces
As of PHP 5, the SPL has some very interesting (and largely obscure) classes and interfaces hidden away. The three I've listed here allow any class that implements them to act as an array.
Why would you want to do this? Well, for example, let's say that your random someMethodReturningUsers() now returns your own class AwesomeArray. Does the end-user need to know that? Not really. If they like, they can continue on oblivious and execute our two-step plan above. Everything's peachy. But, but... you now know better. Because AwesomeArray not only implements those array-like interfaces, it has a get() method that takes an integer and returns that array index.
Bam! Your process now looks like $user = $User->someMethodReturningUsers()->get(0);. But that's not all, you get the best of both worlds. You can have you cake and eat it too, because as well as chaining methods as shown, you can still use the AwesomeArray returned as you would a regular array. Iterate over it using foreach() (that's what the Iterator interface handles), access its indexes (ArrayAccess), and check its length via count() (Countable).
I'm not sure that this is a perfect solution (there may be array methods like array_unique that just don't work) but when used in conjunction with some sugary syntactic goodness, it really is the cherry on top, the finishing touch.
I've included the code below so you can roll your own. Enjoy!
class Result implements ArrayAccess, Countable, Iterator {
private $position = 0;
private $data = array();
public function offsetSet($offset, $value) {
if ($offset == ''){
$this->data[] = $value;
} else {
$this->data[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->data[$offset]);
}
public function offsetUnset($offset) {
unset($this->data[$offset]);
}
public function offsetGet($offset) {
return $this->data[$offset];
}
public function get($index){
return $this->data[$index];
}
public function count(){
return count($this->data);
}
public function rewind(){
reset($this->data);
}
public function current(){
return current($this->data);
}
public function key(){
return key($this->data);
}
public function next(){
return next($this->data);
}
public function valid(){
return $this->current() !== false;
}
public function size(){
return count($this->data);
}
}

As an aside, I've always hated the LINQ-Style Method-Chaining for sql querying. I mean SQL is a trivial language, and is well-known. I don't see why I would want it in method-form. But that's just me :)
Otherwise, it seems quite nice and cool to turn something into an array like that.
Out of interest, does PHP allow operator-overloading of the [] operator? Cause it could be done that way as well then. I know that's how it's done in C#.