Fluent Interfaces Require Fluent Situations

My friend and coworker Mike Naberezny wrote recently of fluent interfaces (a.k.a. object chaining). You should read more about it there, but in the mean time, here’s an example usage provided by Mike for a new customer order with multiple lines and a shipping priority:

$customer->newOrder()
         ->with(6, ‘TAL’)
         ->with(5, ‘HPK’)->skippable()
         ->with(3, ‘LGV’)
         ->priorityRush();

The idea is that the fluent interface makes it very easy to read the resulting code in a way that flows naturally. This is cool, but I want to add a caveat to his examples.

I think, for a fluent interface to be effective, you need situations where you actually have all that information at one time so that you can chain the methods in a fluid way. In the above case, we actually know what the whole order is, what the shipping priority is, etc. But very often (I would say “almost always”) you *don’t* know what the whole customer order is. Instead, you are more likely to iterate through the order lines as the customer adds them, or as you retrieve them from some data source. You might need something more like Mike’s initial contra-example:

$order = $customer->newOrder();
foreach ($line as $item) {
    $order->with($item['number'], $item['type']);
}

That’s not to say that a fluent interface cannot perform in such a way (it can if written to allow for it). My point is that writing class methods in a fluent interface style may not be worth the effort when you don’t often expect to have all the necessary information at once; however, if you *do* expect to have that information, it can be very nice. For example, I could see where a fluent interface could be quite effective in something like Solar_Sql_Select. Currently, you need to do this:

$select = Solar::object('Solar_Sql_Select');
$select->cols('*');
$select->from('table_name');
$select->where('colname = ?', $value);
$select->order('colname DESC');
$result = $select->fetch('all');

But with a fluent interface, one could do it this way (which seems very clean to me at this point):

$select = Solar::object('Solar_Sql_Select');
$select->cols('*')
       ->from('table_name')
       ->where('colname = ?', $value)
       ->order('colname DESC');
$result = $select->fetch('all');

Anybody have thoughts on this particular style of expression?

A Dearth of Blogging Lately

A number of people have emailed me to note that my blog has died since I started at Zend. Very sorry to disappoint those of you who look forward to my missives. 🙁

The main reason for my lack of authorship has been that this blog (with some notable exceptions) has mostly been about whatever PHP project I’m currently working on. Since I’m now working on Zend-internal stuff, none of which can be public right now, there’s not much I am at liberty to write about, especially given that my other public projects are mostly stable in one sense or another. That, and my free time has been in short supply given the holidays, family commitments, etc.

Having said that, look for more in this space over the next few days and weeks; in the mean time; thanks for your patience. 🙂