my $LoggerClass = $self->logger_class();
This gives you lots of flexibility. Then, you have the best of both worlds: you can define a convention, and, in true perl fashion, you can define how to do something different from convention. For example, someone may want a bunch of apps to share the same logger class, so they just override logger_class, and you continue unconcerned about the change. Your default could even do much what you are doing already (although you're using @_isa_parts and $_isa_parts - two entirely different variables...):
sub logger_class
{
ref(shift) . '::Debug';
}
This also gives you some more flexibility where you can return an object instead of a class, or you can change the default in some other way. Or you can require the desired class to ensure it's loaded, ... whatever. It's localised. Though, if you want that extra flexibility, I'd suggest allowing the logger class to be passed in and possibly cached.
sub logger_class
{
my $self = shift;
my $set = 0;
# was a (new?) class passed in?
$self->{__PACKAGE__ . ':logger_class'} = shift and $set++ if @_;
# if we don't have one, construct the default.
unless (exists $self->{__PACKAGE__ . ':logger_class'})
{
$self->{__PACKAGE__ . ':logger_class'} = ref(shift) . '::Debug';
$set++;
}
# if it changed, do any configuration needed.
if ($set)
{
# load the class, etc.
}
# done - return it.
$self->{__PACKAGE__ . ':logger_class'};
}
This would then allow the constructor to an object set its own logger class on an object-by-object basis. Or allow a package to set its logger class by overriding and passing in the new value (to allow the initialisation to occur):
# in some other package...
sub logger_class
{
my $self = shift;
$self->SUPER::logger_class('Some::Shared::Package::Debug');
}
Lots of alternatives. Depends on how overboard you wanna go with this newfandangled "OO" fad ;-) | [reply] [d/l] [select] |
my @_isa_parts = split '::' => ref($self );
pop @_isa_parts; # pop off the ::DB stuff ...
my $LoggerClass= ((join "::" => @_isa_parts) . "::Debug");
And yes, this is a perfectly acceptable approach, notice I did not say "quick hack" because I don't honestly see anything wrong with this. As long as you thoroughly comment this, and always stick to that nameing convention (which is a good thing to do in a framework anyway), you should have no issues.
Of course, the moment you step outside of the boundries of your naming conventions, it all falls apart. But even then the breakage is in a single place (the function which contains the code above), and you shouldn't have too much trouble fixing it.
Remember, encapsulation and convention are your friends when build or working with code frameworks.
| [reply] [d/l] |
sub action {
if ( DEBUG ) {
my $loggerClass= $self->_getLoggerClass();
my $loggerHandle= eval($loggerClass ."::getLoggerHandle()");
}
}
sub _getLoggerClass {
my ( $self )= @_;
my @_isa_parts = split '::' => ref($self );
return $_isa_parts[0] . '::Debug::Logger';
}
MyApp::Debug::Logger::getLoggerHandle() is a factory method that tosses me a new Logger object from a pool
I kind of like how this works now, and could conceivably consolidat a bit of code with this. So i'm wondering if anyone has a suggestion on how I could call a package function with this, and pass in variables.
i.e., do something like:
my $loggerClass= $self->get_loggerClass();
eval('&'.$loggerClass .'::writeToLoggerHandle($self,$text)');
I don't know if that shows a clear intent or not
| [reply] [d/l] [select] |
First off, I wouldn't use the leading underscore. In Perl convention, that means "don't call (or override) me". If that's what you really want, that's fine. But I don't think it is.
Second, why are you only using the root of the object's namespace? That is, if I have both Foo::Bar::Blah and Foo::Baz::Flubbar, you're expecting them both to share the same Foo::Debug? That seems a bit of a strange convention.
Finally, you're evaling way too many strings there ;-)
sub action {
if ( DEBUG ) {
my $loggerClass = $self->_getLoggerClass();
my $loggerHandle = $loggerClass->getLoggerHandle();
}
}
Two major differences here. First, this doesn't use eval STR. Any time you can avoid eval STR is a good thing. Not just because of possible nasty code-injection attacks (which probably aren't a major concern here), but also because we can avoid the overhead of another parse/compile session.
Second major difference is that we'll be passing in the $loggerClass as the first parameter to getLoggerHandle. In this case, it doesn't look like a bad thing since you aren't passing anything in anyway, so most likely getLoggerHandle will just ignore its parameter, no harm done to your API. A side effect here is that if _getLoggerClass returns a full-fledged object, that will get passed in instead, though that likely won't change anything. Another side effect is that if the logger class does not define getLoggerHandle, but one of its parent classes (if any) do, this will get properly dispatched up the @ISA hierarchy. This is handy if, for example, your logger class has a generic form, and the one we're using just overrides a few things.
On to your question. (That & is always unnecessary - unless you know what you're doing, but that's another SoPW.) Try this out:
my $loggerClass = $self->_getLoggerClass();
$loggerClass->writeToLoggerHandle($self, $text);
As I said earlier, this will pass in $loggerClass as the first parameter. Unlike the getLoggerHandle function which didn't take any parameters, this one does. So you'll need to take that into account inside the function, by shifting off that first parameter, and likely as not discarding it. There is another way, however. But it's rarely used, and will probably confuse more than a few people, so I don't suggest it - I merely bring it up for completeness.
$loggerClass->can('writeToLoggerHandle')->($self, $text);
Here we ask the perl interpreter whether the class can do this method. It will check the @ISA hierarchy for us, and return a CODE reference if it succeeds. We then dereference that code reference with the next arrow, and pass in its parameters.
But don't do that. It's confusing. ;-)
| [reply] [d/l] [select] |