As soon as you take a reference to a method, you have disassociated it from its instance, and converted it to a function. (which it is anyway but blah, blah ...:)
The way around this is to generate an anonymous sub that calls the method you want and passes the instance handle ($self), retaining it via the closure mechanism, and pass a reference to that anonymous sub as the callback
$parser->handler(
start => sub { $self->_add_link( @_ ) },
'tagname,attr'
);
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
| [reply] [d/l] |
| [reply] |
$object->method( 1, 2, 3 );
What perl does is
- Inspects $object, which is a blessed reference of some kind, and finds out the package that it was blessed into.
You can see this yourself if you print a blessed reference and you get something like My::Package=HASH(0x1d154d8). In this case $object is a hashref that was blessed into the package My::Package.
- It then looks up the address of the sub named 'method' in the package My::Package, and then calls that address passing the list $object, 1, 2, 3 in @_.
Hence, the first thing you shift off @_ within the method is $self. Ie. The object upon which the method was called.
However, when you take the address of a method
my $codref = \&$object->method;
and then later invoke it (or have the parser invoke for you),
$coderef->( 1, 2, 3 );
Perl no longer recognises that you are invoking a method rather than a function, and therefore doesn't add $object to the stack. Even if it knew that this was a method call, it no longer knows which package (or which instance of that package) was used to derive the address of the method. So it wouldn't know what $object to pass.
Indirecting the call through a closure simply allows you to retain the instance handle along with the method to be invoked, with the slight penalty of the two step process of getting there.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
| [reply] [d/l] [select] |
When I have to do this, I simply create a very small anonymous sub. Something like:
$parser->handler(sub { $self->add_link(@_) },
'tagname,attr');
That code's not tested, but you get the idea.
Update:Remove bad parameter I forgot to delete.
Update:Probably should be $self-> instead of $parser->. Fixed.
| [reply] [d/l] [select] |
local $instance = $self;
$parser->handler(start => \_add_link, 'tagname,attr');
...
sub _add_link {
my $self = $instance;
...
This makes _add_link a sort of spring-loaded method call.
Update: Forget this, and go with BrowserUk's suggestion below. Using a closure is a superior approach.
| [reply] [d/l] [select] |
That isn't going to work. As soon as the method containing the the call to $parser->handler() exits, (or the nearest local scope), then the value assigned to $instance will be forgotten as the global $instance reverts to its former value and whne the _add_link() routine is called back by the parser, $instance could have just about any value.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
| [reply] |
| [reply] [d/l] |