How to get values and ref types from caller package

D

Dodger

Hiya, all,

I've been racking my brain on how to get values and references of all
the variables in the caller's package.

Basically, the situation I have is that there's a sort of proxy-
requirer method that's taking up a fair amount of overhead. I'd love
to just get rid of it, but the whole thing is pretty old and massive
and has a lot of code, not all of which I have access to, and the
thing is there because different modules may be require-d in depending
on those settings.

One of the other problems is that some of the coders have decided to
go ahead and call this thing numberous times even when they don't need
to. Rather than try and hunt down every instance of someone calling
for Foo when they already have a Foo object, i wanted to be able to
look into the symbol table for the caller, find all the variables
there, and check to see if any of the scalars are, in fact, already a
Foo, and, if so, just to return that and do nothing else. This would
bypass the need to check to make sure it's the right *kind* of Foo
because the first time a Foo was grabbed it would be and the
environment doesn't change at runtime. It's safe to trust the former
Foo is the right kind of Foo.

Now I've been able to grab the list of variables back easily enough
with:
my $ppst;
print "Getting symbol table of caller $pkg<br/>\n";
my $getcaller = '$ppst = \%' . $pkg . '::';
print "About to eval $getcaller<br>\n";
eval $getcaller;
print "eval error: $@<br>\n" if $@;
for my $stk (sort {lc $a cmp lc $b} keys %{$ppst}) {
...
}

But the problem is I can't get a ref out of those things, or a value,
or anything. I've tried *foo{THING} syntax, I've tried turning off
strict refs in the block, the works. Everything is acting undef
(unless I do eval '$varcopy = *' . $pkg . '::' . $stk . '{SCALAR}' --
that annoyingly returns an anonymous scalar ref every time and the
perldocs seem to be vague on why or even if they should.

Anyway, thanks in advance for any advice/info/explanation of what I
may be doing wrong...

Here's the current sandbox code (I keep changing it though):

my ($pkg, $filename, $line, $subroutine, $hasargs,
$wantarray, $evaltext, $is_require, $hints, $bitmask) = caller(1);
print <<"EOF";
Called package_setup on $package<br/>
<pre>
Caller:
package: $pkg
Filename: $filename
Line: $line
Subroutine: $subroutine
Has args? $hasargs
Wantarray? $wantarray
Eval text: $evaltext
is require? $is_require
hints: $hints
bitmask: $bitmask
</pre>
EOF

if (grep /$package/, keys %INC) {
print "<b>Already loaded as:</b><br/><br/>";
print " ---- $_<br/>" for sort {lc $a cmp lc $b} grep /
$package/, keys %INC;
print "<br/><br/>\n";
my $ppst;
print "Getting symbol table of caller $pkg<br/>\n";
my $getcaller = '$ppst = \%' . $pkg . '::';
print "About to eval $getcaller<br>\n";
eval $getcaller;
print "eval error: $@<br>\n" if $@;
for my $stk (sort {lc $a cmp lc $b} keys %{$ppst}) {
no strict 'refs';
# print "Checking $stk<br/>\n";
our $varcopy;
*varcopy = ${$pkg.'::'.$stk} or next;

if (ref $varcopy) {
my $reftype = ref $varcopy;
print "Caller $pkg has a ref $stk, type $reftype<br/>
\n";
}
else {
my $val;
print "value of \$${pkg}::$stk == $varcopy<br/>\n";
}
}
print "<hr/>\n";
}
else {
print "Not yet loaded<hr/><br/><br/>\n";
}
 
R

Randal L. Schwartz

Dodger> One of the other problems is that some of the coders have decided to
Dodger> go ahead and call this thing numberous times even when they don't need
Dodger> to. Rather than try and hunt down every instance of someone calling
Dodger> for Foo when they already have a Foo object, i wanted to be able to
Dodger> look into the symbol table for the caller, find all the variables
Dodger> there, and check to see if any of the scalars are, in fact, already a
Dodger> Foo, and, if so, just to return that and do nothing else. This would
Dodger> bypass the need to check to make sure it's the right *kind* of Foo
Dodger> because the first time a Foo was grabbed it would be and the
Dodger> environment doesn't change at runtime. It's safe to trust the former
Dodger> Foo is the right kind of Foo.

That seems like the hard way. Why don't you just cache the result from
Foo->new, using some sort of aspect programming (replace ->new with something
that watches the inputs and return values from the real ->new)?
 
D

Dodger

Dodger> One of the other problems is that some of the coders have decided to
Dodger> go ahead and call this thing numberous times even when they don't need
Dodger> to. Rather than try and hunt down every instance of someone calling
Dodger> for Foo when they already have a Foo object, i wanted to be able to
Dodger> look into the symbol table for the caller, find all the variables
Dodger> there, and check to see if any of the scalars are, in fact, already a
Dodger> Foo, and, if so, just to return that and do nothing else. This would
Dodger> bypass the need to check to make sure it's the right *kind* of Foo
Dodger> because the first time a Foo was grabbed it would be and the
Dodger> environment doesn't change at runtime. It's safe to trust the former
Dodger> Foo is the right kind of Foo.

That seems like the hard way. Why don't you just cache the result from
Foo->new, using some sort of aspect programming (replace ->new with something
that watches the inputs and return values from the real ->new)?

Thanks, Mr Schwartz! (A little wowed because this feels like if I'd
posted a question on a DOS batch script and gotten a reply from Bill
Gates... only not as evil seeming).

I'm going to do what I can in that vein. For the moment, though, I've
at least made the average time go down from .0887 to .036 seconds,
which is a plus, just by actually checking %INC for the right file and
just using the existing constructor if possible. Killed 5 our of 11
spurious requires that way. Also checked through @INC for the right
file to require if I have to instead of doing an eval "require..."
which seems to have helped some.

I think the next big speed-up I can do at the moment without ...
well... higher-ups wrote some of the base code... in the 90s...
anyway... I've gotten the package loader to not be the slowest thing
happening on the page, so I get to shift gears and figure out which
MySQL SELECTS are taking too long, what indices they aren't using, and
so on.
 
D

Dodger

Dodger> One of the other problems is that some of the coders have decided to
Dodger> go ahead and call this thing numberous times even when they don't need
Dodger> to. Rather than try and hunt down every instance of someone calling
Dodger> for Foo when they already have a Foo object, i wanted to be able to
Dodger> look into the symbol table for the caller, find all the variables
Dodger> there, and check to see if any of the scalars are, in fact, already a
Dodger> Foo, and, if so, just to return that and do nothing else. This would
Dodger> bypass the need to check to make sure it's the right *kind* of Foo
Dodger> because the first time a Foo was grabbed it would be and the
Dodger> environment doesn't change at runtime. It's safe to trust the former
Dodger> Foo is the right kind of Foo.

That seems like the hard way. Why don't you just cache the result from
Foo->new, using some sort of aspect programming (replace ->new with something
that watches the inputs and return values from the real ->new)?

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[email protected]> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Out of curiosity, though... even if this isn't the right way to go,
how can I do this if some time it is the right (or only) solution? Is
there a way to peek right into and get the variables out of the
calling package, maybe even manipulate them?
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top