PHP method chaining or fluent interface? PHP method chaining or fluent interface? php php

PHP method chaining or fluent interface?


It's rather simple, really. You have a series of mutator methods that all return the original (or other) object. That way, you can keep calling methods on the returned object.

<?phpclass fakeString{    private $str;    function __construct()    {        $this->str = "";    }        function addA()    {        $this->str .= "a";        return $this;    }        function addB()    {        $this->str .= "b";        return $this;    }        function getStr()    {        return $this->str;    }}$a = new fakeString();echo $a->addA()->addB()->getStr();

This outputs "ab"

Try it online!


Basically, you take an object:

$obj = new ObjectWithChainableMethods();

Call a method that effectively does a return $this; at the end:

$obj->doSomething();

Since it returns the same object, or rather, a reference to the same object, you can continue calling methods of the same class off the return value, like so:

$obj->doSomething()->doSomethingElse();

That's it, really. Two important things:

  1. As you note, it's PHP 5 only. It won't work properly in PHP 4 because it returns objects by value and that means you're calling methods on different copies of an object, which would break your code.

  2. Again, you need to return the object in your chainable methods:

    public function doSomething() {    // Do stuff    return $this;}public function doSomethingElse() {    // Do more stuff    return $this;}


Try this code:

<?phpclass DBManager{    private $selectables = array();    private $table;    private $whereClause;    private $limit;    public function select() {        $this->selectables = func_get_args();        return $this;    }    public function from($table) {        $this->table = $table;        return $this;    }    public function where($where) {        $this->whereClause = $where;        return $this;    }    public function limit($limit) {        $this->limit = $limit;        return $this;    }    public function result() {        $query[] = "SELECT";        // if the selectables array is empty, select all        if (empty($this->selectables)) {            $query[] = "*";          }        // else select according to selectables        else {            $query[] = join(', ', $this->selectables);        }        $query[] = "FROM";        $query[] = $this->table;        if (!empty($this->whereClause)) {            $query[] = "WHERE";            $query[] = $this->whereClause;        }        if (!empty($this->limit)) {            $query[] = "LIMIT";            $query[] = $this->limit;        }        return join(' ', $query);    }}// Now to use the class and see how METHOD CHAINING works// let us instantiate the class DBManager$testOne = new DBManager();$testOne->select()->from('users');echo $testOne->result();// ORecho $testOne->select()->from('users')->result();// both displays: 'SELECT * FROM users'$testTwo = new DBManager();$testTwo->select()->from('posts')->where('id > 200')->limit(10);echo $testTwo->result();// this displays: 'SELECT * FROM posts WHERE id > 200 LIMIT 10'$testThree = new DBManager();$testThree->select(    'firstname',    'email',    'country',    'city')->from('users')->where('id = 2399');echo $testThree->result();// this will display:// 'SELECT firstname, email, country, city FROM users WHERE id = 2399'?>