Method Chaining in PHP

suggest change

Method Chaining is a technique explained in Martin Fowler’s book Domain Specific Languages. Method Chaining is summarized as

Makes modifier methods return the host object, so that multiple modifiers can be invoked in a single expression.

Consider this non-chaining/regular piece of code (ported to PHP from the aforementioned book)

$hardDrive = new HardDrive;
$hardDrive->setCapacity(150);
$hardDrive->external();
$hardDrive->setSpeed(7200);

Method Chaining would allow you to write the above statements in a more compact way:

$hardDrive = (new HardDrive)
    ->setCapacity(150)
    ->external()
    ->setSpeed(7200);

All you need to do for this to work is to return $this in the methods you want to chain from:

class HardDrive {
    protected $isExternal = false;
    protected $capacity = 0;
    protected $speed = 0;

    public function external($isExternal = true) {
        $this->isExternal = $isExternal;        
        return $this; // returns the current class instance to allow method chaining
    }

    public function setCapacity($capacity) {
        $this->capacity = $capacity;        
        return $this; // returns the current class instance to allow method chaining
    }

    public function setSpeed($speed) {
        $this->speed = $speed;        
        return $this; // returns the current class instance to allow method chaining
    }
}

When to use it

The primary use cases for utilizing Method Chaining is when building internal Domain Specific Languages. Method Chaining is a building block in Expression Builders and Fluent Interfaces. It is not synonymous with those, though. Method Chaining merely enables those. Quoting Fowler:

I’ve also noticed a common misconception - many people seem to equate fluent interfaces with Method Chaining. Certainly chaining is a common technique to use with fluent interfaces, but true fluency is much more than that.

With that said, using Method Chaining just for the sake of avoiding writing the host object is considered a code smell by many. It makes for unobvious APIs, especially when mixing with non-chaining APIs.


Additional Notes

Command Query Separation

Command Query Separation is a design principle brought forth by Bertrand Meyer. It states that methods mutating state (commands) should not return anything, whereas methods returning something (queries) should not mutate state. This makes it easier to reason about the system. Method Chaining violates this principle because we are mutating state and returning something.

Getters

When making use of classes which implement method chaining, pay particular attention when calling getter methods (that is, methods which return something other than $this). Since getters must return a value other than $this, chaining an additional method onto a getter makes the call operate on the gotten value, not on the original object. While there are some use cases for chained getters, they may make code less readable.

Law of Demeter and impact on testing

Method Chaining as presented above does not violate Law of Demeter. Nor does it impact testing. That is because we are returning the host instance and not some collaborator. It’s a common misconception stemming from people confusing mere Method Chaining with Fluent Interfaces and Expression Builders. It is only when Method Chaining returns other objects than the host object that you violate Law of Demeter and end up with Mock fests in your tests.

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


Classes and objects:
* Method Chaining in PHP

Table Of Contents
2 Arrays
4 Types
10 Cookies
11 Classes and objects
14 JSON
15 SOAP
17 cURL
19 XML
21 Traits
35 UTF-8
36 URLs
38 PHPDoc
41 Loops
44 Closur
72 YAML
77 Cache
78 Streams
81 PDO
82 SQLite3
83 Sockets
87 MongoDB
93 IMAP
94 Redis
95 Imagick
102 APCu
108 PSR