
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.
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!

#1 by zack on November 1st, 2009
| Quote
I’m becoming more and more impressed with you as a developer. I’m definitely subscribed..
#2 by mandoy on November 2nd, 2009
| Quote
wow,, this method chaining is cool
#3 by 3m masr on November 7th, 2009
| Quote
awesome !!
it’s my first introduction to the magic __call() , really cool idea !
#4 by Super Duper on December 25th, 2009
| Quote
Apparently, you have Gamal Abdel Nasser as a fan.
#5 by Luis Cruz on January 14th, 2010
| Quote
Hello, awesome code…
is out there something for handle getters tricks? in adittion to common magic getters.
Regards from MX
#6 by Tommy Tooth on February 3rd, 2010
| Quote
Hi,
how is it possible that if one of the method in the chain does not work, for example, then the chain breaks up and returns some error. for example if I want to do this:
$result = $db->connect()->query(….)->get_result();
if ($result === FALSE)
echo “something went wrong …”;
You see above that either connect or query can both fail .. how is it possible that the chain breaks up in either method and I get the error returned ???
#7 by Burak on February 3rd, 2010
| Quote
I don’t think a “returned error” would be very fitting in this case. Instead you can just throw exceptions. Then you wrap the whole thing as a try-catch block.
#8 by siddarth on February 9th, 2010
| Quote
please tell about how to user javascript codings in anchor tag
#9 by Addy on March 30th, 2010
| Quote
hi,
Good topic
Thanks
Addy
#10 by Ian Moone on February 3rd, 2011
| Quote
Hi! Thanks for this article… great read. I just wonder if this approach is better than __set and __get. I’m using __set to do all the validation… and with this approach, __call… I can’t do that…
Hoping for some enlightenment hihi^^
#11 by Amisima on July 18th, 2011
| Quote
I’m not sure whether this is the correct way but I also am using the __set function to perform my validation and I have updated the __call to call my __set function which will then function as it was prior to adding the __call function.
I’m sure it’s extra processing but for the time being it does the trick…
#12 by T on February 19th, 2011
| Quote
Hi,
great tutorial as always, i was able to go through the first 14 on nettuts, going to continue with the rest, as well as the doctrine fusion here.
these instructions are always intuitive and adequate, keep up the great work!
#13 by Çağdaş on March 26th, 2011
| Quote
great jobs! (on the nettuts and this
)
i got used to handle with codeigniter easily, thanks to you…
and this is very usefull article too…
(İstanbul’dan sevgilerle….)
#14 by karlisba on April 25th, 2011
| Quote
Hi.
This idea actually reduce lot of code lines for some of my PHP classes which include fully or half chaining system.
Nice tutorial. I knew about chaining pattern before, but I’ve never thought of using it with __call method, thanks for idea.
#15 by Regal on May 24th, 2011
| Quote
Excellent! I honestly never knew about this stuff. Quick question… would this work with let’s say “get_” functions.. I see nothing really gets returned, so I was wondering if I were to return information to the magic function, would it treat it as a method.
i.e.
$class->function1->function2
Function 2 returns a value, so would PHP parse it as
$class->function1->value
Pingback: Web Development Resources August 2011 « Data Integrated Entity
Trackback: curso PHP
Pingback: PHP Method Chaining, plus Magic Setters (similar to jQuery) | PHP and Stuff | FRANCESCO DI FUSCO
Pingback: Web Development Resources August 2011 | Data Integrated Entity
#16 by DHT on December 1st, 2011
| Quote
very nice chain method tutorial .. my first impresion of __call
Lol ..regards
Trackback: blu ray 3d player reviews