Fluent Interface in PHP using Singletons

A Fluent interface is a way to chain code together to make statements more comprehensive and understandable. Looking at the Wiki page you can tell that there is no examples in PHP. It *IS* possible to create a fluent interface in PHP if you return the object on each function.

It is important to note that for fluent interfaces, you want to assume any action is being taken on the last “subject”. Here is a simple class that demonstrates this principle :

class T {
        static $results=array();

        static function insert( $number ) { //Inserts a number into the array
                array_push( self::$results, $number );
                return new static;
        }

        static function add( $number ) { //Adds to the last inserted number
                self::$results[] = array_pop(self::$results) + $number;
                return new static;
        }
        static function results() { //Display results
                foreach(self::$results as $k=>$v) {
                        echo "{$k} : {$v}<BR>\n";
                }
        }
}

It starts with the static function “chain”. This returns a object that can be chained to other methods in the chain singleton. I choose to push and pop variables as a way to keep focus on the immediately added number. For example :

T::insert(4)->
        add(2)->
        insert(12)->
        insert(2)->
        add(1)->
        results();

Would produce the results :

0 : 6
1 : 12
2 : 3

To make my life easier, I decided to create a singleton helper class. This would allow you to register, tab through ( via the point() function ), and execute commands chaining from the source.

You can view my PHPChainer Chain Helper at GitHub. The example of usage would look like this :

include_once("chainer.php");

class fruit {

	var $type = "fruit";
	var $color = "";

	function description() {
		echo "Its a fruit";
		echo "<BR>";
	}

	function eat() {
		echo "Tastes fruity!";
		echo "<BR>";
	}
}

class apple extends fruit {

	function __construct() {
		$this->type = "apple";
		$this->color();
	}

	function color() {
		$colors = array(
			"red","green","yellow","rotten"
		);
		shuffle($colors);
		$this->color = $colors[0];
	}

	function description() {
		echo "its an apple";
		echo "<BR>";
	}
}

class grannysmith extends apple {

	function __construct() {
		parent::__construct();
		$this->color = "green";
	}

	function eat() {
		echo "Great!";
		echo "<BR>";
	}
}

// Now for the magic

C::register( new fruit() ,"fruit")->
	description()->
	register( new apple() ,"apple")->
	description()->
	register( new grannysmith() ,"granny")->
	point("apple")->
	eat();

The output would be :

Its a fruit
Its an apple
Tastes fruity!

PHPChain can also be extended to be a generator, or the base of a whole new framework. I like to pair it to request routers such as the AltoRouter. Here is what serving up a webpage would look like in chains with the AltoRouter via anonymous functions :

Router::map("GET|POST /users/[i:user_id]", function($params) {
	C::register( new user( $params["user_id"] ), "user" )->
		register( new template(), "template")->
		assign( "user",C::fetch("user") )->
		run( function() {
			// You can do stuff here too
		} )->
		point( "template" )->
		render( "users.php" );
}

Chaining is also powerful with a Facade pattern.

Leave a Reply