Daily Archive for September 15th, 2009

chain()

Like many other languages, PHP is home to method chaining, a pattern that allows writing several mutators on the same object without having to name it more than once. A typical example can be found in the Zend Framework for configuration of e-mails, among other things :

$mail = new Zend_Mail();
$mail -> setBodyText('This is the text of the mail.')
      -> setFrom('somebody@example.com', 'Some Sender')
      -> addTo('somebody_else@example.com', 'Some Recipient')
      -> setSubject('TestSubject');

This is a very simple trick that is accomplished by having every mutator return the object itself.
However, the PHP syntax rules forbid calling a member function on the result of a new-expression, so that you always require a two-step sequence: initialize the object, then call its chain of mutators.

Of course, a simple solution is to use a function:

 function chain($obj) { return $obj; }

 $mail = chain(new Zend_Mail())
   -> setBodyText('This is the text of the mail.')
   -> setFrom('somebody@example.com', 'Some Sender')
   -> addTo('somebody_else@example.com', 'Some Recipient')
   -> setSubject('TestSubject');

In a similar vein, there’s the matter of using the method chaining pattern on objects that were not designed for that. This is where a quick wrapper can come in handy:

 // Define the appropriate class and function
 class WithWrapper
 {
   public $value;
   public function __construct($obj) {
     $this -> value = $obj;
   }
   public function __call($name, $args) {
     assert (count($args) === 1);
     $this -> value -> $name = $args[0];
     return $this;
   }
 }

 function with($obj) {
   return new WithWrapper($obj);
 }

 // A typical record class
 class Person
 {
   var $age;
   var $firstName;
   var $lastName;
   var $married;
 }

 // Create entry for Jane
 $jane = with(new Person())
   -> age(24)
   -> firstName("Jane")
   -> lastName("Smith")
   -> married(false)
   -> value;

 // Jane gets married
 with($jane)
   -> lastName("Brown")
   -> married(false);

This is starting to look like Visual Basic



680 feed subscribers
(readers who polled a feed this week)