Fluent Interfaces in PHP

      3 Comments on Fluent Interfaces in PHP

p. Fluent Interfaces are not a new programming construct. However, PHP developers have not been able to use them until PHP 5. Now with PHP 5 and the ability to directly dereference an object, PHP developers can build objects using fluent interfaces.

p. For those who do not recognize this particular buzzword fluent interfaces is a way of chaining methods of an object together. By having a method return a reference to the object itself, @return $this;@ you chain methods together like this @$this->methodOne()->methodTwo()->methodThree();@. This can make your code easier to read, and that is the point of using fluent interfaces, making your code easier to read.

p. To be honest, until recently I had not paid much attention to fluent interfaces. You can write good programs without them. These days however, I’m doing a lot of work with the “Zend Framework”:http://framework.zend.com and the framework contributors make use of fluent interfaces. So I decided to dig a little deeper and find out if I was missing anything.

p. I started my digging “here”:http://weierophinney.net/matthew/. Since I talk with Matthew on a regular basis I know that he uses fluent interfaces in some of his Zend Framework contributions. Matthew pointed me to his friend “Mike Naberezny”:http://www.mikenaberezny.com. About this time last year Mike wrote a post in his blog talking about “fluent interfaces”:http://www.mikenaberezny.com/archives/35. In it he had this to say.

bq. In PHP 4, it was not possible to do chaining, but one of the great new features of PHP 5 is that it supports directly deferencing objects returned by methods. It might sound complicated, but it’s really not and it has the potential to greatly improve the readability of some code.

p. In his blog post, Mike’s blog points to a “blog post by Martin Fowler”:http://martinfowler.com/bliki/FluentInterface.html where Martin discusses, among other things, the origins of the name “fluent interfaces”. Martin shows some good but Java centric examples of fluent interfaces in his post but the most interesting thing he contributed to the discussion was this line explaining in more detail than “make things look pretty” why fluent interfaces are useful.

bq. Probably the most important thing to notice about this style is that the intent is to do something along the lines of an internal “DomainSpecificLanguage”:http://martinfowler.com/bliki/DomainSpecificLanguage.html. Indeed this is why we chose the term ‘fluent’ to describe it. The API is primarily designed to be readable and to flow. The price of this fluency is more effort, both in thinking and in the API construction itself. The simple API of constructor, setter, and addition methods is much easier to write. Coming up with a nice fluent API requires a good bit of thought.

p. Both Mike and Martin discuss that fact that fluent interfaces are not for every situation. Like most programming techniques, there are times when it will simplify you code and make life easier. However, there are time when trying to implement them just does not make sense. As with any design decision, careful thought is recommended before implementing fluent interfaces.

p. Mike takes Martin’s Java example code and translates it into PHP 5 code so PHP developers can get a feel for how fluent interfaces work and how they can be beneficial. The example that Martin originally wrote and that Mike translated is that of an order entry system. In it they show the following two pieces of code. The first example is a snippet from a class in which the method makeNormal() is used to create an order in the system. The makeNormal() method is part of the order object.

p. Next, they show the fluent interface version of the code.

p. As you can see, the second example is easier to read, assuming you understand that the with() method adds lines to the order. As stated earlier, this bit of magic is accomplished by the @with()@, @skippable()@, and @priorityRush()@ methods retuning a reference to the object. (@$this@) That is the one and only secret to fluent interfaces. Mike has a HelloWorld example in “his post”:http://www.mikenaberezny.com/archives/35 for those who want to see more code.

p. Paul M. Jones, also discusses fluent interfaces on his “blog”:http://paul-m-jones.com/blog/?p=188, responding to Mike’s original post. While Paul’s examples all revolve around his framework, Solar, the advice he gives on the subject makes his post well worth the read.

bq. I think, for a fluent interface to be effective, you need situations where you actually have all that information at one time so that you can chain the methods in a fluid way.

p. This will limit where you can use fluent interfaces but if you consider it carefully before implementing them, it will help you avoid having to re-code to remove them later.

p. In response to both Mike and Paul’s posts, Andi Gutmans posted about “fluent interfaces”:http://andigutmans.blogspot.com/2005/12/fluent-interfaces.html on his blog. In his post Andi gave more detailed advice on when he thinks they should be used.

bq. The million dollar question is when to actually use this kind of programming style. Of course there are no definitive answers but I suggest to consider the following points:
a) Use your intuition. If you don’t feel this will address the 95% of common use-case for using your interface, then it’s probably not the right solution for what you’re trying to accomplish.
b) As Paul noted, if in the common use-case you don’t have all the necessary data available to complete the task in one go, you should think twice about doing it.
c) Probably the most important point: It really has to read well in your language (e.g. English), preferably as a complete sentence. If you can’t read the code out aloud then it’s probably not what you want.

p. Mike talks in his post about using them on set*() methods but warns that using them on just some setters but not all setters will quickly create an unmaintainable situation. As we saw in the example above though, setters are not the only place they are useful. As Andi and Paul have noted, fluent interfaces can be implemented anytime you have all the information necessary to perform all of the tasks and your method does not need to return information directly to it’s caller.

p. This is where my code comes in. I just finished my second iteration of my “TagCloud”:http://www.calevans.com/view.php/page/tagcloud class. (“phpclasses.org page”:http://www.phpclasses.org/browse/package/3587.html) As you can see from the “source code”:http://www.calevans.com/tagCloud/TagCloud.phps I make use of fluent interfaces not only in my setters but in the other methods as well. In my case, only the get*() methods needed to return any information to the calling program. Therefore fluent interfaces worked well for me in this case. The culmination of the work can be see in the public method buildCloud().

p. Because all of the worker methods return @$this@, the buildCloud() method is a mere 2 lines long and very easy to read.

p. A small example of a method would be the @consolidateArray()@ method. IN a tag cloud, you want the tags weighted by frequency so you can score them. This function takes a single dimension array and counts the values in it. The results are stored in the _consolidatedArray property for later use. This method does not need to return any data to it’s caller so it’s a good candidate. It also passes Paul and Andi’s rule that we know all the information beforehand.

p. In reality though, you need more than one method to meet the criteria to make fluent interfaces a good choice. Unless you want to drive the programmer behind you batty, you really need to make it an all-or-nothing effort. Either all (most) of your methods in your class meet the criteria for fluent interfaces or they don’t. If they don’t, don’t try and force it. Having to remember which methods you can chain and which you can’t on a complex piece of code could become a maintenance nightmare.

p. If all of this seems a long way to go for readability, think of this. As PHP matures and more Enterprise scale application are built in it, the ability to produce easy to read code is skill that is actively being sought after.

p. =C=