Trick: Chainable Libraries

You may have seen Laravel's core libraries use method chaining as an elegant way of providing multiple user definable settings to a library, for example the Fluent Query Builder allows you to chain methods together to build your SQL query before executing it, like this..

DB::table('users')->where('name', '=', 'dayle')->take(5)->get();

It's a system that simply makes sense to use, and is very clear to read. Today I am going to help you build chainable classes, so that your libraries will start to feel more 'Laravelish'. (If that isn't a real word we need to make it one.)

I'm going to start by showing you a chainable class, all done.

class Ball
{
    private $size = 1;
    private $color = 'blue';
    private $texture = 'squishy';

    // creator
    public static function make()
    {
        $ball = new Ball();
        return $ball;
    }

    // chain
    public function size($size)
    {
        $this->size = $size;
        return $this;
    }

    // chain
    public function color($color)
    {
        $this->color = $color;
        return $this;
    }

    // chain
    public function texture($texture)
    {
        $this->texture = $texture;
        return $this;
    }

    // trigger
    public function get()
    {
        return "This is a {$this->texture} {$this->color} ball, size {$this->size}.";
    }
}

I bet its not as complicated as you thought it would be! Before we can look at how it works, first you will need to know the three parts of a chainable class. I will use my own names for these parts, feel free to borrow them!

Creator

The creator method is normally static, and is used to create a new instance of the class. It will always return the class instance as the result of the method. In my example the creator is make().

Chains

Chains are methods which alter the class in some way. They are non-static public methods, which set class attributes with the new settings passed to them. Chains will always return the current instance of the class, which is $this.

Triggers

Trigger methods are found at the end of the chain. They are the methods that make use of all of class attributes we have changed. They either perform an action, or return a result.

Let's have a closer look at each part of our class, first the Creator method make().

// creator
public static function make()
{
    $ball = new Ball();
    return $ball;
}

As you can see, a static call to make creates a new instance of our class, and hands it back as the result. So this line of PHP is perfectly acceptable..

$ball = Ball::make();

Similar to..

$ball = new Ball();

Now we know what our creator method does, let's have a closer look at the chain methods..

// chain
public function size($size)
{
    $this->size = $size;
    return $this;
}

// chain
public function color($color)
{
    $this->color = $color;
    return $this;
}

// chain
public function texture($texture)
{
    $this->texture = $texture;
    return $this;
}

The chain methods are making changes to class attributes using the parameters provided to them, and returning the current object instance, which can always be found using $this.

So now we could use the following code..

$ball = Ball::make();
$ball->color('red');

This is perfectly fine, but it could look better. The make() method is returning an object instance, so we can attach our chain method on to the end, to call the method on the object instance that has been returned. Therefore the code..

$ball = Ball::make()->color('red');

Which will perform in the same way as the last code snippet. We can attach as many chains as we want, because they all return the current object instance, for example..

$ball = Ball::make()->color('red')->size(5)->texture('fuzzy');

The chains can also be added in any order we like.

To make use of our changes we will need to use a trigger method, in our class the trigger method is get().

// trigger
public function get()
{
    return "This is a {$this->texture} {$this->color} ball, size {$this->size}.";
}

The get() method makes use of all our newly set class attributes and returns a short sentence describing the ball that we have made.

echo Ball::make()->size(4)->get();

gives..

This is a squishy blue ball, size 4.

In this example I have simply supplied the size() chain, which works fine because I have set default values for all my class attributes.

So now we know how to make a chainable class, and some 'Laravelish' libraries, go forth and make clean, expressive bundles!