I suppose I should have summarized what I learned from that
experiment, putting myself more squarely on topic: Simply put, a
Fluent interface let me move from
$_input->addCheck('Integer');
$_input->addCheck('Range',3,9);
$_input->addCheck('NonEmpty');
to
$_input->addCheck('Integer')
->addCheck('Range',3,9)
->addCheck('NonEmpty');
with almost no effort. Not a huge timesaver, but I kept it in
because I find the necessary code that I'll use repeatedly to be less
cluttered and easier to read. Less experienced developers who will
have to work with my code felt the same way. It just feels like less
labor. And as a solution, it suited this problem well, mirroring how
most people mentally approached the issue - making it easier for them
to understand the code at a glance.
I elaborated on that problem because it was specifically the nature
of the problem that led me to Fluent interfaces as being part of the
solution. I needed to set up a complex configuration within the
object, but needed only a very simple response from it. Like others
pointed out, a SQL query is a very simple thing, but building one may
involve many seemingly simple steps that occur in no prescribed
particular order, and you don't need the result until the
configuration is complete. Fluent interfaces can hide complexity.
1) Fluent interfaces seem to work best when most of your methods
alter the internal characteristics of an object. Setting properties,
not Getting them. You can't really use a fluent interface when you
actually NEED a specific response from your method: they work by
returning a reference to the object itself instead of returning a
value - that way, the response they deliver is set up and ready to
receive a new, unrelated method call. You can combine the fluent
with the conventional, but then you have to remember that any non-
fluent call must occur last in a string of requests. I could have
easily written:
$test = $_input->addCheck('Integer')
->addCheck('Range',3,9)
->addCheck('NonEmpty')
->check('4.97');
if($test)? ...
but I found it more legible to stay conventional when using non-
fluent methods.
Basically, if you have configuration processes that often need to be
called sequentially, but not always in the same sequence, Fluent
interfaces can smooth the rough edges.
2) Fluent interfaces probably work better with thrown exceptions than
they do with error notices. If you generate a non-fatal error in the
middle of a string of fluent method calls, how do you cope with it?
Return the object anyway and let the next method continue? Not return
the object and get a new error because your error message can't
accept a method call? Bail out at the point of error within your
method instead of pointing where the error was caused? Exceptions
move the error handling outside of the predicted flow of the fluent
interface, making them easier to deal with. Your errors represent
what actually went wrong instead of being a side-effect or symptom of
something that went wrong earlier in the process.
To sum up, Fluent interfaces seem to be a great solution when
combined with a certain set of well-defined problems and practices.
PHP5 makes them even more useful. They save some keystrokes, they
can improve code legibility, they can make PHP code more intuitive
for people who weren't the ones who created it. I don't think they
make code execution any faster (or slower, for that matter). It's
worth knowing about them, but they probably shouldn't change your day
to day practices. As with most techniques, it becomes a matter of
knowing when to apply this particular tool.
Tim Stiles,
WatchMaker,
Icomex.com
DallasPHP.org
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php