How to use Method Chaining in PHP

How to use Method Chaining in PHP

In this tutorial, we’ll take a look at How to use Method Chaining in PHP. Method Chaining is nothing but the concatenation of multiple methods to increase the readability of code and avoid putting all the code in the single function.

One of the major changes between PHP4 and PHP5 is that in PHP5 method can return objects. We will first see the basics of method chaining and then we’ll look into examples with explanation.

Method Chaining is mainly used to implement Fluent Interface in an object-oriented API to achieve code readability. The term Fluent Interface was first invented by Eric Evans and Martin Fowler back in 2005. Note that method chaining is not Fluent Interface. Rather Fluent Interface uses method chaining.

Using Fluent Interface, now we can allow multiple methods to be called on the same object using $this variable.

Why we need method chaining in PHP?

We can only use method chaining where we need current objects all the information whether that contains a string, integer, boolean or any object.

Let’s understand the old way of calling methods and then we’ll look fantastic real life example which is (similar kind of) used by many frameworks

<?php

class studentDetails {

 private $id = 0;
 public $name = '';
 public $address ='';

 public function setStudentId($id) {
  $this->id = $id;
 }

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

 public function setStudentAddress($address) {
  $this->address = $address;
 }

public function getStudentInfo() {
  return 'student '. $this->name. ' of id '.$this->id. ' stays at '. $this->address;
 }
}

$obj = new studentDetails();
$obj->setStudentId(1423);
$obj->setStudentName('John');
$obj->setStudentAddress('LA');

print_r($obj->getStudentInfo());
// OUTPUT

student John of id 1423 stays at LA

In the above example, we call each method individual method using $obj and set properties in the same methods. This process looks quite hectic because we are individually invoking methods and assigning value to each property.

Let’s rewrite studentDetails class with the use of method chaining way-

<?php


class studentDetails {

 public $id = 0;
 public $name = '';
 public $address ='';

 public function setStudentId($id) {
  $this->id = $id;
  return $this;
 }

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

 public function setStudentAddress($address) {
  $this->address = $address;
  return $this;
 }
 
 public function getStudentInfo() {
  return 'student '. $this->name. ' of id '.$this->id. ' stays at '. $this->address;
 }
 
}

$obj = new studentDetails();
$studentInfo = $obj->setStudentId(1423)
                   ->setStudentName('John')
                   ->setStudentAddress('LA')
                   ->getStudentInfo();

print_r($studentInfo);

Now, our code looks cleaner and more readable. In this example, we called multiple methods using same Object $obj and finally executed getStudentInfo() which takes all the already initialized variable using individual method.

Now, let’s see the real world example. In this example we are going to create DBHandler class. So here is the example-

<?php

class DBHandler
{
	public $columns = array();
	public $table;
	public $where;
	public $limit;
	public $query_elements = [' SELECT ', ' FROM ', ' WHERE ', ' LIMIT '];

	public function select($columns)
	{
		$this->columns = $columns;
		return $this;
	}

	public function from($table)
	{
		$this->table = $table;
		return $this;
	}

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

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

	public function result($selectedColumns = "*")
	{
		$query = $this->query_elements[0];
		// if the columns array is empty, select all columns else given columns
		if (count($this->columns)>=1 && !empty($this->columns[0])) {
			$query .= implode(', ', $this->columns);
		} else {
			$query .= $selectedColumns;
		}

		$query .= $this->query_elements[1];
		$query .= $this->table;

		if (!empty($this->where)) {
			$query .= $this->query_elements[2];
			$query .= $this->where;
		}

		if (!empty($this->limit)) {
			$query .= $this->query_elements[3];
			$query .= $this->limit;
		}
		return $query;
	}
}

In the above example, we have created multiple methods (select(), from(), where(), limit()) which will assign each value to the respective property and then finally we created function whose responsibility will be to summon all the properties and create a select statement query.

Let’s run our first Test Case-

$objDBHandler = new DBHandler();
$objDBHandler->select(['']);
$objDBHandler->from('accounts');
$objDBHandler->where('id=1');
$objDBHandler->limit(10);
echo $objDBHandler->result();
// OR
echo $objDBHandler->select([''])
                  ->from('accounts')
                  ->where('id=1')
                  ->limit(10)
                  ->result();

In the old way, we have invoked all the methods individually and passed required parameter to them and these values are stored in the individual property which is then stored in the $this variable and then we invoked result() method to build and return query.

But we can avoid this overhead and use the method chaining in PHP and execute all the methods in single call. Both ways will print the same query but the later one is more compacted and readable.

// OUTPUT

SELECT * FROM accounts WHERE id=1 LIMIT 10

Second Test Case- Pass columns to select() function

$objDBHandler = new DBHandler();
$objDBHandler->select([
	'firstname',
	'lastname',
	'address',
	'city']
)->from('accounts')->where('id = 1');
echo $objDBHandler ->result();
// OUTPUT

SELECT firstname, lastname, address, city FROM accounts WHERE id = 1

How to use Method Chaining in PHP in Different ways-

  • Using Traits
  • Using Interface
  • Inside child class

Method Chaining Using Traits

<?php

trait samsungGalaxy
{
	public function smartPhoneName()
	{
		$this->phoneName = __TRAIT__;
		return $this;
	}

	public function battery($batteryCapacity)
	{
		$this->batteryCapacity = $batteryCapacity;
		return $this;
	}
}

class Mobile
{
	public $mobileType;
	public $phoneName;
	public $batteryCapacitype;

	use samsungGalaxy;

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

	public function getMobileInfo()
	{
		return $this->phoneName . " is a " . $this->mobileType . " mobile having battery capacity of " . $this->batteryCapacity;
	}
}

$obj = new Mobile();
echo $obj->smartPhoneName()
          ->mobileType('android')
          ->battery('2000mh')
          ->getMobileInfo();
// OUTPUT

samsungGalaxy is a android mobile having battery capacity of 2000mh

Method Chaining Using Interface

<?php

interface MyInterface
{
	public function methodA($methodA);
	public function methodB($methodB);
}

abstract class MyClassName implements MyInterface
{
	public  function methodA($methodA)
	{
		$this->methodAproperty = $methodA;
		return $this;
	}

	public abstract function methodB($methodB);
}

class MyChildClassName extends MyClassName
{
	public $methodAproperty, $methodBproperty;

	public  function methodB($methodB)
	{
		$this->methodBproperty = $methodB;
		return $this;
	}

	public function getAllMethodsInfo() 
	{
		return "Interface methods are " . $this->methodAproperty . " & " . $this->methodBproperty;
	}
}

$obj = new MyChildClassName;
echo $obj->methodA('method A')
         ->methodB('method B')
         ->getAllMethodsInfo();
// OUTPUT

Interface methods are method A & method B

Using Child Class

<?php

class Mobile
{
	public $mobileType;
	public $phoneName;
	public $batteryCapacitype;

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

class samsungGalaxy extends Mobile
{
	public function smartPhoneName()
	{
		$this->phoneName = __CLASS__;
		return $this;
	}
	public function battery($batteryCapacity)
	{
		$this->batteryCapacity = $batteryCapacity;
		return $this;
	}

	public function getMobileInfo()
	{
		return $this->phoneName . " is a " . $this->mobileType . " mobile having battery capacity of " . $this->batteryCapacity;
	}
}

$obj = new samsungGalaxy();
echo $obj->smartPhoneName()
	->mobileType('android')
	->battery('2000mh')
	->getMobileInfo();
// OUTPUT

samsungGalaxy is a android mobile having battery capacity of 2000mh

Static Method Chaining

In case of static method chaining, there are no additional changes need to do in the class apart from converting return $this; to return new static;
This is because we know that, inside a static function, there is no existence of $this because static method belongs to class level and not object level.

Let’s take the below example for our understanding of static method chaining.

<?php

class studentDetails {

 public static $id = 0;
 public static $name = '';
 public static $address ='';

 public static function setStudentId($id) {
  static::$id = $id;
  return new static;
 }

 public static function setStudentName($name) {
  static::$name = $name;
  return new static;
 }

 public static function setStudentAddress($address) {
  static::$address = $address;
  return new static;
 }
 
 public static function getStudentInfo() {
  return 'student '. static::$name. ' of id '.static::$id. ' stays at '. static::$address;
 }
}

echo studentDetails::setStudentId(1423)
->setStudentName('John')
->setStudentAddress('LA')
->getStudentInfo();

// OUTPUT

student John of id 1423 stays at LA

Conclusion

This way we have understood what method chaining in PHP is, how we can use it in the codebase, different ways of using method chaining.

One Comment

Olivier June 20, 2020

very good explanation, thank you!