Typgeglobs ausgeben und dereferenzieren?
AlexBausW
- perl
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 :-)
#============================
package LOG;
use strict;
use vars qw(*LOG);
#***********************************************
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;
}
}
#********************************
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,"; "; }
}
#==================================
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);
}
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
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);
sub test {
my $globe = shift;
print $$globe; # ist hier uninitialisiert
}
Gruß AlexBausW
Gruss
Kai
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
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
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.
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