|Perl: the Markov chain saw|
I've never been a huge advocate of OO; I use objects when it's convenient. However, the more code I write, the more I begin to realise that I should be using objects a lot more. A recent solution to a problem I had re-enforced this for me. Although this is probably pretty obvious to a lot of Monks, I thought I'd share my story with you, in case someone finds it useful.
The ProblemI've often been suspicious of the 'use objects unless you have a really good reason not to' attitude, but as I learn more, I find that even if there doesn't seem to be a really good reason to use OO at the time you write something, when it comes to maintenance, OO can often make your life a lot easier.
I've got a mod_perl application that uses HTML::Template throughout. At the time I wrote it, there wasn't any off-the-shelf framework that I really liked (I'd probably use Catalyst now), and since it was a fairly simple app, I rolled my own.
This just consisted of a Handler that created my own Request object, and passed this to every 'crontroller' function. It included an Apache::Session object, database connection, etc.
The problem was, I needed to add an item to the main menu (displayed on every page) for administrator users only. Previously, there hadn't even been an administrator user, but I did have a 'top.html' template, included by every other template with the menu.
I wrote some code to read the administrator flag from the DB, and store it in the session - nothing tricky there.
I didn't like the thought of passing an adminstrator flag every time I made a call to HTML::Template's param(), so I obviously needed to wrap it.
Luckily, HTML::Template is OO, so all I needed to do was sub-class it. This was pretty straight forward:
At the same time, I figured I'd default that pesky die_on_bad_params to off, since I hardly ever use it.
Then all I had to do was change every call to HTML::Template->new() to MyApp::HTML::Template->new() - a simple find & replace.
Passing the Flag
Ok, so I had a wrapper for every call to HTML::Template, but now I needed the flag to be passed in to each template. Again, I didn't want to do this every time I called param(), so I obviously needed to override it.
Great, but now I had a problem. The Request object wasn't accessable from my wrapper class - it's out of scope of course. And I didn't want to pass *that* in every time.
After a bit of thinking, I realised I just needed to make my Request class a singleton. This was as simple as inheriting from Apache::Singleton (this module was necessary rather than Class::Singleton, so that the singleton is destroyed at the end of the mod_perl request).
Then, from the param method, I can simply call MyApp::Request->instance() and I'll have the request object with the flag I need, which can then be passed to param().
Update: Fixed a spelling error
Update 2: Updated constructor, as per jeffa's suggestion.