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


In reply to Re: Trapping acces to variables in-code by davido
in thread Trapping acces to variables in-code by gkelly

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.