accessing object variables from callback function

K

kaisung

Hi,

I'm trying to write a Class which uses XML::parser. XML::parser uses
callback functions. If I use an object method as the callback
function, how can I access object variables from within that callback
function if it doesn't get passed a reference to $self? Here's what I
have so far:

-----BEGIN PERL-----
package Test;

use XML::parser;

sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ };
bless($self, $class);
return $self;
}

sub load {
my $parser = new XML::parser(ErrorContext => 2);
$parser->setHandlers(Start => \&_start_handler);
$parser->parsefile("file.xml");
}

sub _start_handler {
# In this function, I want to set $self->{var}, however don't have
# access to $self
}

sub getVar {
my $self = shift;
return $self->{var};
}
-----END PERL-----


Thanks in advance,
-Kai
 
A

anno4000

Hi,

I'm trying to write a Class which uses XML::parser. XML::parser uses
callback functions. If I use an object method as the callback
function, how can I access object variables from within that callback
function if it doesn't get passed a reference to $self?

Then don't use the object method, but use a closure that calls the
object method. You're not saying of what class the object method
is supposed to belong and what $self is going to be. I'll assume
XML::parser and $parser respectively. See below (code untested).
Here's what I
have so far:

-----BEGIN PERL-----
package Test;

use XML::parser;

sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ };
bless($self, $class);
return $self;
}

sub load {
my $parser = new XML::parser(ErrorContext => 2);
$parser->setHandlers(Start => \&_start_handler);

Use a closure that encloses the object you want to call _start_handler()
with:

$parser->setHandlers(Start => sub { $parser->_start_handler });
$parser->parsefile("file.xml");
}

sub _start_handler {
# In this function, I want to set $self->{var}, however don't have
# access to $self
}

You do if it is called from the closure.

Anno
 
B

Brian McCauley

Then don't use the object method, but use a closure that calls the
object method. You're not saying of what class the object method
is supposed to belong and what $self is going to be. I'll assume
XML::parser and $parser respectively. See below (code untested).

Actually it's more likely that the OP intended Test::load to be a
method.
Use a closure that encloses the object you want to call _start_handler()
with:

$parser->setHandlers(Start => sub { $parser->_start_handler });

sub load {
my $self = shift;
my $parser = new XML::parser(ErrorContext => 2);
$parser->setHandlers(Start => sub { $self->start_handler } );
}
 
K

kaisung

Thanks for the tip on closures, that's what I was looking for. For
completeness, here's what my final program looks like.

-Kai


-----BEGIN MyTest.pm-----
#################################
# A simple class that loads an
# XML file and returns the number
# of tags in the file.
#################################
package MyTest;

use XML::parser;

# Create a new object
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = { @_ };
bless($self, $class);
return $self;
}

# Load an xml file and count the number of tags
sub load {
my $self = shift;
my $file = shift;
my $parser = XML::parser->new(ErrorContext => 2);
$parser->setHandlers(Start => sub { $self->_start_handler(@_); });
$parser->parsefile($file);
}

# Return the number of tags in loaded xml file
sub numTags {
my $self = shift;
return $self->{numTags};
}

# Private method
sub _start_handler {
my $self = shift;
my $p = shift;
$self->{numTags}++;
}
1;
-----END MyTest.pm-----

-----BEGIN mytest.pl-----
#!/usr/bin/perl -w

use MyTest;

my $test = MyTest->new();

$test->load("test.html");
print "numTags = " . $test->numTags() . "\n";
-----END mytest.pl-----
 
D

Dr.Ruud

(e-mail address removed) schreef:
package MyTest;

Missing:

use strict ;
use warnings ;
use XML::parser;

# Create a new object
sub new { [...]
}

# Load an xml file and count the number of tags
sub load { [...]
}

# Return the number of tags in loaded xml file
sub numTags { [...]
}
[...]
1;
-----END MyTest.pm-----

-----BEGIN mytest.pl-----
#!/usr/bin/perl -w

Missing:

use strict ;

If your perl is not very old, replace the -w (in the shebang) by the
lexical

use warnings ;

use MyTest;

my $test = MyTest->new();

Variant:

my $test = new MyTest ;

$test->load("test.html");
print "numTags = " . $test->numTags() . "\n";


Variant:

$test->load('test.html') ;
print "numTags = @{[ $test->numTags() ]}\n" ;

or even:

print "numTags = $test->{numTags}\n" ;

(which bypasses the method)
 
B

Brian McCauley

Dr.Ruud said:
(e-mail address removed) schreef:


Variant:

my $test = new MyTest ;

Yes, TIMTOWTDI, but most (not all) Perl experts prefer the ->
print "numTags = $test->{numTags}\n" ;

(which bypasses the method)

(which is bad)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,162
Latest member
GertrudeMa
Top