Method Chaining with PHP

Method chaining is a fluent interface design pattern used to simplyify your code. If you've used frameworks like Zend or jQuery, you probably have some experience with chaining. Essentially your objects return themselves, allowing you to "chain" multiple actions together.

Before I dive into the DIY aspects, here's an example of some cluttered code we can simplify with chaining. Let's say we want to fetch some data using Zend_Db. Assume we have a company database and want to know how many hours our employees this month. We could use a SQL query like this:

 

SELECT E.LastName, E.FirstName, E.Department, SUM(H.HoursLogged) AS HoursThisMonth FROM	Employees AS E INNER JOIN Hours AS H ON H.EmpID = E.EmpID WHERE H.DateLogged >= '12/1/2009' ORDER BY LastName, FirstName

 

This is perfectly acceptable to use, but hard to read. Using Zend_Db_Select to build the query, we could write it like this:

$startDate = '12/1/2009';
$db = Zend_Db::factory( /*options*/ );
$select = $db->select();
$select->from(
array('E' => 'Employees'),
array('LastName, FirstName, Department')
);
$select->joinInnerUsing(
array('H' => 'Hours'),
'EmpID',
array('HoursThisMonth' => 'SUM(HoursLogged)')
);
$select->where('H.DateLogged > ?', $startDate);
$select->order(array('LastName', 'FirstName'));

 

What Chaining Looks Like

That certainly looks better, but see how every line starts with "$select->"? We can eliminate that repetition and clean up the code through chaining. Since Zend_Db_Select already implements chaining, we can do this:

$startDate = '12/1/2009';
$db = Zend_Db::factory( /*options*/ );
$select = $db
->select()
->from(
array('E' => 'Employees'),
array('LastName, FirstName, Department')
)
->joinInnerUsing(
array('H' => 'Hours'),
'EmpID',
array('HoursThisMonth' => 'SUM(HoursLogged)')
)
->where('H.DateLogged > ?', $startDate)
->order(array('LastName', 'FirstName'))
;

The whole query is built with a single line of code! This sample is much easier to read and maintain.

 

When Do I Implement Chaining?

Method chaining is best implemented on functions/methods that modify their parent object. They usually set a variable or perform some action without returning a result. Here are some examples of good candidates for chaining:

$log->write("Something just happened.");
$log->write("And it happened again.");
$mail->to('[email protected]');
$mail->subject('Test');
$mail->body('Hello World!');
$mail->send();
$cache->clear();
$cache->add("somekey", "andavalue");

 

How To Implement It

Implementation is extremely simple - simply return the object instance once the method has completed:

function someMethod (params)
{
/* do stuff */
return $this;
}

That's all you need to do! Since some of the original methods didn't return a value, returning "$this" shouldn't affect your scripts at all. Now your code looks like this:

$log->write("Something just happened.")
->write("And it happened again.")
;
$mail->to('[email protected]')
->subject('Test')
->body('Hello World!')
->send()
;
$cache->clear()
->add("somekey", "andavalue")
;	

Not all your methods need to (or should) chain. For example, the "$mail->send()" function above should probably return false if the message wasn't sent:

if($mail->to('[email protected]')->subject('Test')->body('Hello World!')->send())
echo "Message Sent!";
else
echo "Oops, something went wrong!";

 

You certainly don't have to use chaining in everything you do, but I'm sure you'll find some good uses for it.