Variablen und Symboltabellen
Symboltabellen
von Packages
Wie im Abschnitt Packages
beschrieben, gibt es in Perl Namensräume (Packages), die
jeweils ihre eigenen Variablen besitzen. Diese Variablen sind in
sogenannten Symboltabellen gespeichert. Die Tabelle eines jeden
Package ist in Form eines Hash abgelegt; um darauf zuzugreifen
stellt man dem Package-Namen ein "%
" voran und
hängt zwei Doppelpunkte "::
" an.
#!/usr/local/bin/perl
### Package "main"
$main_var1; @main_var2 = (2,3);
package hallo; ### Package "hallo"
$hallo_var;
package main; ### wieder zurück in "main"
foreach $v (keys %hallo::) { print "hallo> $v\n" } foreach $v (keys %main::) { print "main> $v\n" }
|
|
Die erzeugte Ausgabe ist recht umfangreich, da auch alle vordefinierten
Variablen in der Symboltabelle von main
enthalten sind.
Man beachte, daß in %main::
(man kann hier stattdessen
auch die Kurzform %::
verwenden) nur der jeweilige Name
einer Variablen erscheint; ein Präfix (wie etwa "$
")
wird weggelassen.
Hier ein Ausschnitt der Programmausgabe:
hallo> hallo_var main> main_var1 main> main_var2 main> v main> hallo:: main> 0
|
|
Die Symboltabelle des Packages hallo
enthält
nur die Variable $hallo_var
, während sich in main
neben den explizit verwendeten Variablen $main_var1
,
@main_var2
und $v
auch der Name der
neuen Symboltabelle %hallo::
findet. Außerdem
stehen dort vordefinierte Variablen wie $0
, welche
den Namen des gerade ausgeführten Skripts beinhaltet.
[Seitenanfang]
Globale Variablen und our()
Wie im obigen Abschnitt schon gezeigt wurde, kann auf Variablen, die "einfach
so" deklariert oder verwendet werden, innerhalb des jeweiligen Packages
direkt zugegriffen werden. Solche Variablen werden global genannt, da
sie an jeder Stelle des Programms zur Verfügung stehen; selbst wenn
sie in einem Unterprogramm deklariert werden.
Oft sind globale Variablen zwar praktisch, sie können ein
Programm aber auch schnell unübersichtlich machen. Deswegen
empfiehlt es sich, globale Variablen nur dort zu verwenden, wo sie
notwendig sind. Damit man nicht versehentlich globale Variablen
einführt, sollte man immer das Pragma use strict
verwenden.
Benutzt man use strict
, so muß man bei jeder
Variable angeben, welchen Gültigkeitsbereich sie haben soll.
Globale Variablen markiert man ab Perl 5.6.x mit der Deklaration
our()
.
#!/usr/local/bin/perl -w
use strict;
use 5.6.0; ### "our" funktioniert ### erst ab Perl 5.6.0
our $var = 123;
sub routine { our $vr = "Hallo"; print "$vr\n"; }
routine();
print "$var\n"; print "$main::vr\n";
|
|
Auf eine mit our
deklarierte Variable kann man innerhalb
des umschließenden Blocks, der Datei oder dem Argument der
Funktion eval()
zugreifen, ohne einen Packagenamen
angeben zu müssen. Im obigen Beispiel ist der Gültigkeitsbereich
von $var
die gesamte Datei, während der "einfache"
Zugriff auf $vr
nur innerhalb des Unterprogramms
routine
(in diesem Falle der umschließende Block)
möglich ist. Allerdings kann man mit Hilfe des
Packagenamens auch außerhalb der Subroutine auf $vr
zugreifen.
Eine our
-Variable ist u.U. sogar über Package-Grenzen
hinweg sichtbar, es kann jedoch jedes Package jeweils eigene Variablen
mittels our
deklarieren.
#!/usr/local/bin/perl -w
use strict;
use 5.6.0; ### "our" funktioniert ### erst ab Perl 5.6.0
our($v1,$v2);
$v1 = 1; $v2 = 2;
package name;
print "$v1 $v2\n";
our $v2 = 9;
print "$v1 $v2 $main::v2\n";
|
|
Die Variable $v1
ist in der ganzen Datei einfach über
ihren Namen verfügbar, während es von $v2
zwei Exemplare gibt. Nach der Deklaration im Package
name
kann auf die in main
deklarierte
Variable über den Package-Namen zugegriffen
werden. Ohne Angabe des Packages wird die zuletzt deklarierte
our
-Variable verwendet (unabhängig vom aktuell
gültigen Package).
Für ältere Perl-Versionen (< 5.6.0) deklariert man
globale Variablen außerhalb von Blöcken mit Hilfe von
my()
(siehe folgenden Abschnitt).
[Seitenanfang]
Lexikalische Variablen mittels my()
Jede Variable, die mit our
deklariert oder
auch "einfach so" ohne eine Deklaration verwendet wird, wird in die Symboltabelle
des jeweils aktuellen Packages aufgenommen.
Deklariert man dagegen eine Variable mit dem Operator my
,
so wird die entsprechende Variable in einer anderen Tabelle
abgelegt, auf die kein expliziter Zugriff möglich ist.
#!/usr/local/bin/perl -w
use strict;
use 5.6.0; ### "our" funktioniert ### erst ab Perl 5.6.0
our $var_1; my $var_2;
$var_1 = 42; $var_2 = "Perl";
foreach $v (keys %::) { ### Symboltabelle von "main" if($v =~ /^var/) { print "$v\n" } }
|
|
Hier erscheint in der Programmausgabe nur "$var_1
", nicht
aber "$var_2
".
Neben der Tatsache, daß my
-Variablen in einer
eigenen Tabelle verwaltet werden, ist von besonderer Bedeutung, daß
sie nur einen recht beschränkten Gültigkeitsbereich
besitzen. Eine durch
my
erzeugte Variable steht nur in dem aktuellen Block (definiert
durch geschweifte Klammern "{...}
"), der aktuellen Datei
oder innerhalb eines Arguments von eval()
zur Verfügung.
Außerhalb davon existieren diese Variablen nicht, es
ist also (im Gegensatz zu our
-Variablen)
auch mit Hilfe des Package-Namens dort kein Zugriff möglich
Es kann in einem Package durchaus zwei Variablen gleichen
Namens geben: eine in der Symboltabelle und eine, die durch
einen Aufruf von my
entstanden ist. In einem solchen
Falle wird bei einfacher Verwendung des Bezeichners auf die
my
-Variable zugegriffen.
#!/usr/local/bin/perl -w
use strict;
use 5.6.0; ### "our" funktioniert ### erst ab Perl 5.6.0
our $ab = "main"; { my $ab; $ab = "Block";
print "$ab\n"; ### "Block" print "$main::ab\n"; ### "main" } print "$ab\n"; ### "main"
|
|
Im Block in der Mitte des Programms existiert neben "$ab
"
der Symboltabelle von main
(Zugriff über voll
qualifizierten Namen "$main::ab
" möglich) auch
eine my
-Variable gleichen Namens. Letztere verschwindet
aber wieder, sobald der umschließende Block verlassen wird.
Es ist übrigens durchaus möglich, my
-Deklarationen
zu "schachteln":
#!/usr/local/bin/perl -w
use strict;
my $ab = "main"; { my $ab; $ab = "Block"; print "$ab\n"; ### "Block" } print "$ab\n"; ### "main"
|
|
Man bezeichnet solche Variablen als lexikalisch, weil
deren Gültigkeitsbereich schon alleine durch Untersuchung
des Programmcodes feststellbar ist.
Benötigt man in einem Perl-Programm eine lokale Variable,
so sollte man im allgemeinen my
verwenden. Lediglich
in speziellen Situationen ist es angebracht, stattdessen
local
(siehe nächsten Abschnitt)
zu benutzen.
[Seitenanfang]
Dynamische Variablen mittels local()
Auch der Operator local
schränkt den
Gültigkeitsbereich einer Variablen ein. Allerdings
unterscheidet sich der Mechanismus grundlegend von dem
des Operators my
.
Wird eine Variable durch local
deklariert,
so wird der aktuelle Wert dieser Variablen (sofern vorhanden)
gesichert. Anschließend können dieser Variablen
neue Werte zugewisen werden. Wird der Block, in dem die
local
-Deklaration erfolgte, verlassen, so wird
der ursprüngliche (gesicherte) Wert wiederhergestellt.
#!/usr/local/bin/perl -w
$ab = 123; print "Main: $ab\n";
{ local $ab; $ab = 456; print "Block: $ab\n"; }
print "Main: $ab\n";
|
|
Main: 123 Block: 456 Main: 123
|
|
Bei der Deklaration mit local
wird keine
neue Variable auf irgendeinem Stack erzeugt (wie bei my
),
sondern es wird nur der Inhalt neu zur Verfügung gestellt.
Die entsprechende Variable ist also nach wie vor global zugänglich.
Daß die Variable nach wie vor eine globale Variable ist, erkennt
man auch im folgenden Beispiel:
#!/usr/local/bin/perl -w
$x = 'x (main)'; print "Main: \$x = $x\n";
{ local $x = 'x (local)'; print "Block: \$x = $x\n"; print "Symboltabelle: \$::x = $::x\n"; unterpr(); }
print "Main: \$x = $x\n";
sub unterpr { print "unterpr(): \$x = $x\n"; }
|
|
Main: $x = x (main) Block: $x = x (local) Symboltabelle: $::x = x (local) unterpr(): $x = x (local) Main: $x = x (main)
|
|
Sowohl in der (globalen) Symboltabelle als
auch in der Subroutine unterpr()
, die sich, betrachtet
man den Quell-Code des Programms, außerhalb des Blockes mit
der local
-Deklaration befindet, wird für
$x
der Wert "x (local)
"
ausgegeben. Der ursprüngliche Wert wird erst wiederhergestellt,
wenn in der Folge des Programmablaufs der Block verlassen wird, in
dem die local
-Deklaration stattfand.
Da die Gültigkeit von local
-Variablen somit
durch den Programmablauf bestimmt wird, spricht man auch
von Laufzeit- oder dynamischen Variablen.
[Seitenanfang]
Unterschiede zwischen my()
und local()
Die folgende Tabelle zeigt noch einmal schematisch den Unterschied
zwischen my
und local
.
Markiert sind diejenigen Werte,
die ein "print $v;
" an der entsprechenden
Stelle im Code ausgeben würde.
Zeile |
Code |
Symboltabelle von main |
local -Stack |
Tabelle für
my -Variablen |
1 |
$v = 42; |
v = 42 |
|
|
2 |
{ local $v = 100; |
v = 100 |
v = 42 |
|
3 |
{ my $v = 7; |
v = 100 |
v = 42 |
v = 7 |
4 |
} |
v = 100 |
v = 42 |
|
5 |
} |
v = 42 |
|
|
In Zeile 1 wird eine globale Variable "$v
"
angelegt und mit dem Wert 42 belegt. Wird eine local
-Variable
erzeugt (Zeile 2), so überdeckt der neue Wert den alten;
letzterer wird auf einem internen "Stapel" (stack) gesichert.
Unabhängig davon können mit Hilfe von "my
"
lexikalische Variablen erzeugt werden (Zeile 3), die in einer eigenen
internen Tabelle verwaltet werden. Die Gültigkeit der
my
-Variable endet mit der schließenden Klammer in
Zeile 4. Mit dem Blockende in Zeile 5 wird der
Gültigkeitsbereich der local
-Variable verlassen und
der ursprüngliche Wert wird vom Stack wiederhergestellt.
Auf die Variable in der Symboltabelle kann in diesem Beispiel immer mittels
"$main::v
" zugegriffen werden. Existiert zusätzlich
eine my
-Variable, so bezieht sich "$v
"
(ohne "main::
") immer
auf diese (nicht auf das globale "$v
"). Ein Zugriff auf den
local
-Stack ist hingegen nicht möglich.
Eine Situation, in der lokale Variablen nicht mittels my
erzeugt werden können, sind die speziellen in Perl vordefinierten
Variablen, wie etwa $"
(Zeichen, das die
Elemente eines Arrays voneinander trennt, wenn es innerhalb von doppelten
Anführungszeichen interpoliert wird). Man kann wie folgt in einem
Programmblock eine Neudefinition einer globalen Variable
vornehmen, ohne den ursprünglichen Wert explizit sichern und
am Ende wieder zurücksetzen zu müssen:
#!/usr/local/bin/perl -w
$" = ','; @a = (10,20,30); print "@a\n";
{ local $" = ' - '; print "@a\n"; }
print "@a\n";
|
|
10,20,30 10 - 20 - 30 10,20,30
|
|
[Seitenanfang]