AlexBausW: Typgeglobs ausgeben und dereferenzieren?

Hallo Forum,

Vor einiger Zeit kam ich auf die Idee, mir ein Modul zu schreiben, mit dem ich an beliebigen Stellen meiner Skripte, Variablen bzw. deren Zustände ausgeben kann.
Mit Typeglobs funktionierte das auch in der unten geposteten Konstellation auch ziemlich gut, und ergibt:
  Variable: *main::name1
    REF: SCALAR: wert;
  Variable: *main::name2
    REF: ARRAY: 0 => wert; 1 => value;
  Variable: *main::name3
    REF: HASH: eins => wert; zwei => value;

Jetzt habe ich LOG.pm in ein Modul eingebunden, das wiederum von einem Modul  aufgerufen wird, welches in ein Skript eingebunden ist.
Wenn ich ,mit &Log(*variablenname); aufrufe, bekomme ich nur den Variablennamen ausgegeben:
  Variable: *modul::variablenname
aber nicht wie oben die zugehörigen Werte.
In beiden Modulen wird 'use strict;' verwendet. (Den Code spar ich mir hier mal, stelle aber eine Version davon online: http://www.twoforyou.de/test/csv.txt ab Zeile 274, ist markiert, und bitte nicht lachen ;-))

Wieso funktioniert nun der Aufruf aus testlog.cgi, aber nicht mehr aus dem Modul, obwohl die im Modul mit print() ausgegebenen Variablen die korrekten Werte aufweisen?
Habe ich irgendwas übersehen, oder muss ich noch irgendetwas anderes beachten? Sehe ich vielleicht nur den Unterschied zwischen meinem Modul und dem Skript vor lauter Code nicht mehr?

Schon mal vielen Dank für etwaige Hinweise.

Gruß AlexBausW

P.S.: Die Übergabe des Filehandles (LOG) als Typeglob an  &_resolveRefs() habe ich schon mal erfolglos getestet :-(
P.P.S.: Ich hoffe das ist nicht zuviel Code :-)

#============================

LOG.pm

package LOG;

use strict;

Typeglob LOG als Modulvariable

use vars qw(*LOG);

#***********************************************

Schreibt Bezeichner und Werte in Logdatei

sub Log {
   # uebergebene Typeglobs in Array speichern
   my @log = @_;

# Logdatei oeffnen
   open (LOG, ">>$logfile") die "Can`t append to $logfile: $!";
      flock (LOG,2) unless $^O =~ /win/i;
         # Variablen schreiben
         foreach (@log) {
            print LOG "  Variable: ",$_,"\n";
            # Typeglob ist Scalar
            if ( ${$_} ) {
               &_resolveRefs(${$_});
            }
            .
            . # Hier ist der Code fuer Arrays und Hashs
            .
         }
      close LOG;
   }
}

#********************************

loest Referenzen rekursiv auf

sub _resolveRefs {
   # Paramterreferenz
   my $ref = shift;
   # Referenz ist Skalar
   if (ref($ref) eq "SCALAR") {
      print LOG "SCALAR: ";
      &_resolveRefs(${$ref});
   }
   .
   . # Hier ist der Code fuer Arrays und Hashs
   .
   # Referenz ist Referenz
   elsif (ref($ref) eq "REF") {
      print LOG "REF: ";
      &_resolveRefs(${$ref});
   }
   # Ausgabe des Werts der Variablen
   else { print LOG $ref,"; "; }
}

#==================================

testlog.cgi

use LOG;

$scalar = "wert";
@array = ("wert","value");
%hash = ('eins' => "wert", 'zwei' => "value");

&Sub($scalar,@array,%hash);

sub Sub {
   ($name1,$name2,$name3) = @_;
   &Log(*name1, *name2, *name3);
}

  1. Hallo Alex,

    Wenn ich ,mit &Log(*variablenname); aufrufe, bekomme ich nur den Variablennamen ausgegeben:
      Variable: *modul::variablenname
    aber nicht wie oben die zugehörigen Werte.

    Das ganze hat hier wohl nichts mit Deiner vermodularisierung zu tun! Ich denke Dein Problem ist hier, daß Du $primkey per my definiert hast. Dies hat zur Folge, daß $primkey überhaupt nicht in der "symbol table" gelistet wird!!! *primkey steht aber nur für alle Einträge von [$@%*]primkey aus eben dieser Tabelle. Eine Möglichkeit dies zu umgehen, wäre $primkey aus der my-Klammer herauszunehmen und separat per local($primkey); zu defininieren ...

    sub Log {
       # uebergebene Typeglobs in Array speichern
       my @log = @_;

    # Logdatei oeffnen
       open (LOG, ">>$logfile") die "Can`t append to $logfile: $!";
          flock (LOG,2) unless $^O =~ /win/i;
             # Variablen schreiben
             foreach (@log) {
                print LOG "  Variable: ",$_,"\n";
                # Typeglob ist Scalar
                if ( ${$_} ) {
                   &_resolveRefs(${$_});
                }
                .
                . # Hier ist der Code fuer Arrays und Hashs
                .
             }
          close LOG;
       }
    }

    Deine Überprüfung auf Scalar und wohl auch die anderen Varianten finde ich ein wenig riskant. Sollen leere Variablen z.B. nicht ausgegeben werden?
        # Typeglob ist Scalar
        if (definded *{$_}{SCALAR}) {
          &_resolveRefs(*{$_}{SCALAR});
        }
        # Typeglob ist für Array
        if (definded *{$_}{ARRAY}) {
          &_resolveRefs(*{$_}{ARRAY});
        }
        ...

    Das ganze schimpft sich *foo{THING} Syntax. Näheres dazu unter "perldoc perlref".

    Gruß,
        Jörk

  2. Hallo Forum,
    In beiden Modulen wird 'use strict;' verwendet.

    Hier duerfte das Problem liegen. Wenn Du Variable mit 'my' einen lexikalisch Geltungsbereich zuweist werden diese nicht in der Symboltabelle sondern in sogenannte 'scratchpads' gespeichert, die jeder Block/Subroutine enthaelt. D.h. mit my lokalisierte Variable werden nicht durch Typeglobes repraesenteniert

    Beispiel:

    #!perl -w

    use strict;

    my $test = 'test1';
    my @test = ('test2', 'test3');

    test(*test);

    *test zeigt hier nicht auf die oben deklarierten Variable

    sub test {

    my $globe = shift;  
    print $$globe;        # ist hier uninitialisiert  
    

    }

    Gruß AlexBausW

    Gruss
       Kai

  3. Hallo Jörk & Kai,

    Erst mal vielen Dank für die Hinweise. Da hatte ich doch wohl den Unterschied (my()) im Code übersehen :-)
    Jetzt hab ich, glaube ich, auch endlich den Zusammenhang zwischen my(), local() und der Symboltabelle verstanden (wenigstens rudimentär ;-)

    Ich hab ein wenig nachgelesen, nachgedacht, und (da)nachgetestet ;-). Dabei kam ich auf folgende, bis jetzt auch funktionierede Lösung, wie ich meine mit my() deklarierten Variablen doch noch in die Symboltabelle "eintragen" kann.
    Folgende Lösung ist zwar nicht so elegant wie ein einzelner Funktionsaufruf, funktionert aber :-)

    my $var = "wert";
      {
        local (*var) = ($var);
        &Log(*var);
      }

    Also noch mal vielen Dank für Eure Hilfe.

    Gruß AlexBausW

    1. Hallo Alex,

      Hallo Jörk & Kai,

      Ich hab ein wenig nachgelesen, nachgedacht, und (da)nachgetestet ;-). Dabei kam ich auf folgende, bis jetzt auch funktionierede Lösung, wie ich meine mit my() deklarierten Variablen doch noch in die Symboltabelle "eintragen" kann.
      Folgende Lösung ist zwar nicht so elegant wie ein einzelner Funktionsaufruf, funktionert aber :-)

      {
          local (*var) = ($var);
          &Log(*var);
        }

      hier legst Du einen Aliasnamen _nur_ fuer den Skalar $var an, nicht fuer &%@. Das ist also das gleiche wie Log($var).
      (An Unterroutinen, die Typeglob erwarten kann man auch Referenzen
      uebergeben).

      Gruß AlexBausW

      Gruss
         Kai

      1. Hallo Kai,

        {
            local (*var) = ($var);
            &Log(*var);
          }
        hier legst Du einen Aliasnamen _nur_ fuer den Skalar $var an, nicht fuer &%@. Das ist also das gleiche wie Log($var).

        Das war nur ein Beispiel für die Anwendung. Folgendes geht auch:

        do {
           local (*var,*var) = ($var,@var);  
           &Log  (*var);
        }  if    $debug;

        Also legt Perl wohl für jede Variable einen Eintrag in der Symboltabelle an (ich hoffe, daß habe ich so einigermaßen richtig erklärt :-)
        In &Log kann ich per Typeglob auf alle Variablen mit dem entsprechenden Bezeichner zugreifen, und den Bezeicher sowie den Wert der Variablen ausgeben.

        Nochmals Danke für Deine Bemühungen. Ich denke es läuft jetzt so, wie ich es haben möchte :-)

        Gruß AlexBausW

        P.S.: Für Subs brauch ich Typeglobs nicht, da ich nur Variablen loggen möchte.

        1. Hallo Alex,

          Hallo Kai,

          Das war nur ein Beispiel für die Anwendung. Folgendes geht auch:

          do {
             local (*var,*var) = ($var,@var);  
             &Log  (*var);
          }  if    $debug;

          Also legt Perl wohl für jede Variable einen Eintrag in der Symboltabelle an (ich hoffe, daß habe ich so einigermaßen richtig erklärt :-)

          Genau genommen, legt Perl einen Eintrag an (Typeglob), der Zeiger auf alle anderen Datentypen enthaelt. Der Zeiger ist Null, falls der entsprechende Datentyp nicht initialisiert ist. O'Reilly's Fortgeschrittene Perlprogrammierung enthaelt ein ganz interssantes Kapitel ueber dieses Thema.

          Gruß AlexBausW

          Gruss
             Kai