php-method-chaining-1

Quick Disclaimer: Even if you know about PHP5 Method Chaining, don’t skip this article, because we will explore more than just that.

If you’re familiar with jQuery, you might know how it let’s you write short and clean code with the help of method chaining.

Not only will I show you how to accomplish this in PHP5, but I will also combine this feature with magic setter methods with the help of method overloading to make it even nicer.

It’s OK if you don’t know any of these terms. You should still be able to become familiarized with them by reading this article.

download_code

Defining Our Goal

Can you write an Email class that can do this?

<?php
require_once ('Email.php');

$my_email = new Email();
$my_email
	->set_from('test@email.com')
	->add_to('programming@gmail.com')
	->set_subject('Methods Chained')
	->set_body('Some long message')
	->send();

instead of this:

<?php
require_once ('Email.php');

$my_email = new Email();
$my_email->from = 'test@email.com';
$my_email->to []= 'programming@gmail.com';
$my_email->subject = 'Methods Chained';
$my_email->body = 'Some long message';
$my_email->send();

Your answer might be “Yes” if you’re already familiar with PHP Method Chaining.

But can you do it WITHOUT actually implementing the setter methods named “set_from()”, “add_to()” etc… in your class?

PHP Method Chaining in a Nutshell

For those of you not familiar with this term, here is what you need to know:

  • Method Chaining allows you to call multiple methods in a single line.
$my_object->foo()->bar()->taz()->etc();
  • All you need to do is return $this; at the end of your class methods.
class My_Class {

	public function foo() {
		// ... do something
		return $this;
	}

	public function bar() {
		// ... do something else
		return $this;
	}

}

Now your class methods can be called in a chain, resulting in a shorter (and hopefully cleaner) code.

Creating Our Magic Email Class

Before I explain more, I am just going to paste the entire class code here first:

Email.php

<?php

class Email {

	public $from;
	public $to = array();
	public $subject;
	public $body;

	public function send() {

		echo "(not) Sending E-mail <br/>\n".
			"From: {$this->from} <br/>\n".
			"To: ".implode(',',$this->to)."<br/>\n".
			"Subject: {$this->subject} <br/>\n".
			"Body: {$this->body} <br/>\n";

	}

	public function __call($name, $arguments) {

		if (substr($name,0,4) == 'set_') {
			$property = substr($name,4);
			$this->$property = $arguments[0];

		} else if (substr($name,0,4) == 'add_') {
			$property = substr($name,4);
			array_push($this->$property, $arguments[0]);
		}

		return $this;
	}
}

Please Note: I did NOT create any methods named set_from(), set_subject() or add_to() etc…, yet we’ll be able to call these setter methods with the help of some “magic”. Not to metion, we’ll be able to call them in a chain.

Now, let’s analyze the Code

The first part is simple enough. We’re just creating a new class:

class Email {

	public $from;
	public $to = array();
	public $subject;
	public $body;
// ...

Note that the $to property is going to be an array (we can e-mail multiple recipients). We’ll be adding values to it using “add_to()” method call.

Then we write a simple send() method to send our e-mail. (In this case, it’s just a fake one, for testing purposes)

// ...
	public function send() {

		// not actually sending e-mail
		// we're just testing our stuff

		echo "(not) Sending E-mail <br/>\n".
			"From: {$this->from} <br/>\n".
			"To: ".implode(',',$this->to)."<br/>\n".
			"Subject: {$this->subject} <br/>\n".
			"Body: {$this->body} <br/>\n";

	}

Then we create the magic method named __call(). This method gets invoked when a non-existing function (e.g. set_from() or add_to()) has been called.

First argument $name is the name of the method called.
Second argument $arguments are the arguments passed to the method.

For more info: PHP Overloading Methods

// ...
	// this magic method gets called
	// when a non-existing method is called
	public function __call($name, $arguments) {

		// setting a property
		if (substr($name,0,4) == 'set_') {

			// get the property name we want to set
			$property = substr($name,4);
			// assign the value that was passed to this method
			// to the class property
			$this->$property = $arguments[0];

		// adding to an array property
		} else if (substr($name,0,4) == 'add_') {

			// get the property name we want to add to
			$property = substr($name,4);
			// add the value
			array_push($this->$property, $arguments[0]);

		}

		// for method chaining
		return $this;
	}
// ...

In the __call() function above, we do this:

  • If the method call was named set_*, we set the corresponding property value.
  • If the method call was named add_*, we add to the corresponding property an array value.
  • Finally, we return the class instance itself, which allows for method chaining.

Test The Code

If you test the following code:

<?php
require_once ('Email.php');

$my_email = new Email();
$my_email
	->set_from('test@email.com')
	->add_to('programming@gmail.com')
	->set_subject('Methods Chained')
	->set_body('Some long message')
	->send();

You should see this output:

(not) Sending E-mail
From: test@email.com
To: programming@gmail.com
Subject: Methods Chained
Body: Some long message

Thank you for reading

I hope you enjoyed this quick tutorial. If there are any other PHP concepts you would like to learn about, just leave a comment.

Thank you!