loading...

Fluent interface and method chaining in PHP and JavaScript

mofiqul profile image Mofiqul Islam ・1 min read

A Fluent Interface is an object oriented API that provides "more readable" code.
A fluent interface allows you to chain method calls, which results in less typed characters when applying multiple operations on the same object.

read more about fluent interface

Fluent interface let us write code like this:

$programmer->born()->eat()->sleep()->code()->die();

instead of

$programmer->born();
$programmer->eat();
$programmer->sleep();
$programmer->code();
$programmer->die();

Implementation:
A fluent interface is normally implemented by using method chaining to implement method cascading (in languages that do not natively support cascading), concretely by having each method return this (self). Stated more abstractly, a fluent interface relays the instruction context of a subsequent call in method chaining, where generally the context is

  • defined through the return value of a called method
  • self-referential, where the new context is equivalent to the last context
  • terminated through the return of a void context.

from here

A simple PHP example

class Person{
  private $_name;
  private $_sex;
  private $_age;
  private $_height;
  private $_weight;

  public function name($name){
    $this->_name = $name;
    return $this;
  }

  public function sex($sex){
    $this->_sex = $sex;
    return $this;
  }

  public function age($age){
    $this->_age = $age;
    return $this;
  }

  public function height($h){
    $this->_height = $h;
    return $this;
  }

  public function weight($w){
    $this->_weight = $w;
    return $this;
  }
  public function save(){
    $properties = get_object_vars($this);
    $str = '';
    foreach($properties as $property){
        $str .= $property.' ';
    }
    return $str;
  }
}

Now we can call the methods on the object of Person like

$p = new Person();
$res = $p->name('Sonia')->sex('Female')->age('30')->height('5.8')->weight('51')->save();
echo $res; # Sonia Female 30 5.8 51

we can call only few of them

$res = $p->name('Sonia')->sex('Female')->age('30')->save();
echo $res; # Sonia Female 30

we also can call chain methods in deffrent order

$res = $p->name('Sonia')->height('5.8')->weight('51')->sex('Female')->age('30')->save();
echo $res; # Sonia Female 30 5.8 51

Same in JavaScript

var Person = function() {
  this._name = '';
  this._sex = '';
  this._age = '';
  this._height = '';
  this._weight = '';
};

Person.prototype.name = function(name) {
  this._name = name;
  return this;
};

Person.prototype.sex = function(sex) {
  this._sex = sex;
  return this;
};

Person.prototype.age = function(age) {
  this._age = age;
  return this;
};

Person.prototype.height = function(height) {
  this._height = height;
  return this;
};

Person.prototype.weight = function(weight) {
  this._weight = weight;
  return this;
};


Person.prototype.save = function() { 
  let str = '';
  for(let property of Object.keys(this)){
    str += this[property] + ' ';
  } 
  console.log(str);
};

Using it

new Person().name('Sonia').sex('Female').age('30').height('5.8').weight('51').save();
// Sonia Female 30 5.8 51

Discussion

pic
Editor guide
Collapse
eugenevdm profile image
Eugene van der Merwe

This is a great and simple example, so easy to follow. I use Laravel a lot so knowing how to do it is important because Laravel relies heavily on chaining.

I'm struggling to see how one would use a constructor, say you have a lot of setup to always do. Any hints?

Collapse
pdubinski profile image
pdubinski

Be careful, fluent interfaces are considered evil when used in non-builder context.

@ocramius says:
"Fluent Interfaces break Encapsulation
Fluent Interfaces break Decorators (and sometimes Composition)
Fluent Interfaces are harder to Mock
Fluent Interfaces make diffs harder to read
Fluent Interfaces are less readable (personal feeling)
Fluent Interfaces cause BC breaks during early development stages"

Also, your php code breaks clean code (short names) and PSR rules. Not a very good example, especially for young developers

Collapse
sergeytelpuk profile image
Sergey

It's called like a builder pattern. It isn't something new. Visit the link refactoring.guru/design-patterns/b...

Collapse
t3h2mas profile image
Thomas Noe

Not to be confused with the fluent builder pattern:

If your requirement is to build a complex object for which you want to set the mandatory attributes and avoid making any mistakes, then the fluent builder will be more useful rather than the traditional builder pattern.

dzone.com/articles/fluent-builder-...