in reply to Trapping acces to variables in-code
In pondering this question I realized that what you're asking for requires a two-prong approach.
The easy part is you are looking for tied variables. What follows is an example script that creates a tied scalar. The scalar is tied to a class that carps upon access to the variable. Here's the example:
package TieAccess; use strict; use warnings; use Carp; use Tie::Scalar; our @ISA = qw(Tie::StdScalar); my %instances; sub TIESCALAR { my $class = shift; my $var; my $self = bless \$var, $class; $instances{$self} = shift; carp "\$$instances{$self}: TIESCALAR"; return $self; } sub FETCH { my $self = shift; carp "\$$instances{$self}: FETCH ${$self}"; return ${$self}; } sub STORE { my( $self, $value ) = @_; ${$self} = $value; carp "\$$instances{$self}: STORE ${$self}"; return ${$self}; } sub DESTROY { my $self = shift; carp "\$$instances{$self}: DESTROY"; delete $instances{$self}; } 1; package main; my $variable; tie $variable, "TieAccess", "variable"; $variable = 100; print "$variable\n";
The one oddity in the code above is that I used a combination of a normal object oriented approach, along with an "inside out object". I did this so that I could take advantage of the fact that Tie::Scalar has a "Tie::StdScalar" class that already defines all the necessary tie routines. But it does so in a way that doesn't offer any "extra" namespace. The 'inside-out' portion of the class I've created handles the detail of remembering the name of each variable that's tied. This class works only with scalars, but it would be pretty easy to also create classes for arrays and hashes, using this as a sort of guideline.
Now for the tricky part! What you also are trying to do is trap variable creation. This turns out to be a mixed blessing. The good news is that if you trap creation, you can automatically tie all created variables at creation time. That's great. The bad news is that I can't figure out a way to trap the creation of lexicals.
I envisioned a method where you override Perl's CORE::my() routine. But this would have to be completely invisible to the calling script. This presents two challenges: First, my creates a named lexical. It's easy enough to create a lexical and return a reference, but my doesn't do that, it creates a new named lexical, and returns the value assigned to that named lexical. There isn't (to my knowledge) a pure Perl way to obtain the side-effect of creating a new named variable in a lexical namespace. And that leads me to the second problem.
The second challenge (assuming you could somehow find a way around the first challenge) is in creating this new lexical within the proper scope. The idea is that you don't want to create the lexical within the scope of the sub that's doing the creation, you want to create it at the caller's scope. Ick, that sounds trickty too, and there isn't a pure Perl solution.
I looked at PadWalker and considered the possibility of manipulating the hash its peek_my() sub returns. But I just don't know if that's going to work.
I would be interested in hearing if anyone knows if manipulating the hash returned by PadWalker can be used to create a lexical in the calling scope. But unless that turns out to be possible, the fact is that you're dead in the water with regards to the requirement of trapping lexical creation easily.
Update:
After discussing it with demerphq, and being reminded that my has both compiletime and runtime effects, I'm reasonably convinced that you're not going to be able to use PadWalker within an overriding my() sub to create a named lexical at the appropriate scope, in a way that duplicates the compiletime effects of CORE::my(). That being the case, the next thought turns to a source filter that would take the following:
my $variable = 100
...and turns it into...
my $variable; tie $variable, "TieAccess", "variable"; $variable = 100;
But that wouldn't play nice with constructs such as foreach my $variable ( .... ), so it would have to be a pretty sophisticated source filter, and ultimately, I think you're looking at way too much work going down that road.
Probably the best solution is to set a debug flag in the script, and manually create the code to tie the variables that you're interested in, on the condition that the debug flag is set to true. It'll require a little work up front, but the preparation might be made easier by using B::Xref to at least get a listing of the variables you might be interested in tieing.
Dave
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Trapping acces to variables in-code
by gkelly (Acolyte) on Oct 13, 2004 at 18:53 UTC |