I’ve really just begun to learn OOP. I started about a year ago and have written probably 15,000 lines of it. But I wrote it all with hardly any experience looking at other people’s OOP.
Most of my class functions return a value or make a change to the class properties and return true/false. Some of the ones that return a value also save that value into a class property (after first checking if the class property is already set, which can avoid a database call).
Now I’m doing a lot of digging in Magento/Zend and I notice a lot of their class methods return “$this”. As I understand it, unlike in regular functions, class methods that return $this act by reference not by value, so that you get back the same object you started with rather than a copy.
Is returning $this
something that I should be doing much more of? Does it make the code easier to maintain and use? Is returning $this
necessary in order to chain class methods?
5
This is a technique employed to create Fluent Interfaces. If a Fluent Interface is not your goal, then you don’t need to return $this.
Fluent interfaces allow you to write code that looks like this (pseudocode):
private void makeFluent(Customer customer) {
customer.newOrder()
.with(6, "TAL")
.with(5, "HPK").skippable()
.with(3, "LGV")
.priorityRush();
}
It works, because each method call has access to the original object, by virtue of the previous method call returning this
. The above code is more or less equivalent to:
private void makeFluent(Customer customer) {
var newOrder = customer.newOrder()
newOrder.with(6, "TAL");
newOrder.with(5, "HPK", skippable := true);
newOrder.with(3, "LGV");
newOrder.priorityRush();
...
}
this
is not always returned. Sometimes a different object is returned. Linq works like this, returning an IEnumerable
(a lazy representation of a collection, a modified state engine, basically) from each Linq method in the chain.
It requires more effort and forethought to create a fluent interface than it does to simply set all of the parameters in a constructor. You have to figure out whether the object has everything it needs to be fully functional, and it’s not always clear exactly what a given method does, or in what order you need to call the methods. For example:
20.minutes.ago
looks clean, but how does it work, exactly?
http://en.wikipedia.org/wiki/Fluent_interface
http://www.martinfowler.com/bliki/FluentInterface.html
Returning $this returns an instance of the object that the method is a member of. There are lots of cases where you’d want to do this, but until you understand exactly what I just said means and can identify a use case for it, you don’t really need it.
Examples of when to use this:
A btree is an example in PHP of where you would return a child of $this, which isn’t exactly the same thing but I think it has bearing on this discussion.
Writing your own constructor you would always return $this
To clarify about references, when you return $this you’re passing out a reference to the object that the method running is part of. I think PHP’s rules for when it’s operating on a reference vs a value is a little unclear sometimes, but in this case $this is always a reference. To be clear: a reference is always ‘the instance that you had’ and never a copy, whereas a ‘value’ is a copy. These are two types of argument semantics
3
“A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn’t contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.”
The real advantage to returning $this is in object composition design patterns, especially in Magento. Take for example the Mage_Core_Sales_Order_Invoice->capture() which returns $this. This method looks like:
public function capture()
{
$this->getOrder()->getPayment()->capture($this);
if ($this->getIsPaid()) {
$this->pay();
}
return $this;
}
the line:
$this->getOrder()->getPayment()->capture($this);
Passes the invoice model as a reference, very useful in object composition patterns. The return of $this is also a reference. So the method calling ->capture() on an invoice model can continue working with a chained object call next for contextual code readability.