Perl-Programmierung: Gültigkeitsbereich von Variablen


Allgemeines Bearbeiten

In einigen Punkten ist Perl einfacher gestrickt als andere Programmiersprachen, was den Gültigkeitsbereich von Variablen betrifft ist dies jedoch nicht zutreffend. Dabei muss unterschieden werden, zwischen dem Bereich in dem der Variablenname gültig ist und dem Bereich in dem der Inhalt verfügbar ist. Diese beiden Bereiche sind nur für lexikalische Variablen unter bestimmten Bedingungen identisch, nämlich nur dann, wenn keine weitere Referenz auf den Wert der Variable angelegt wurde.

In Perl muss man sich, wie in der Einleitung zu den Variablen erklärt, weniger Gedanken darum machen, ob der Wert auf den ein Variablenname verweist noch gültig ist, da die Speicherverwaltung fast vollkommen selbständig von perl übernommen wird. Nur bei rekursiven Datenstrukturen muss man dafür sorgen, dass der Speicher am Ende der Lebensdauer wieder freigegeben wird, da der Referenzzähler nicht von selbst wieder auf 0 gesetzt wird.

Für Variablen findet man in imperativen Programmiersprachen die Unterscheidung in globale, das heißt im ganzen Programm gültige Variablen und lokale, nur in einem begrenzten Block zum Beispiel einer einzelnen Funktion gültige Variablen. Um Perl zu verstehen, muss man wissen, dass Perl für die Verwaltung seiner Variablen zwei verschiedene Bereiche kennt.

Es gibt die mit dem Schlüsselwort my deklarierten lexikalischen Variablen. Eine andere Beschreibung für sie sind statisch gebundene Variablen, da der Gültigkeitsbereich nach der Deklaration nicht mehr geändert werden kann. Ein solcher Bereich kommt in Perl in verschiedenen Formen vor. Es kann ein Codeblock, eine Funktion, ein eval Aufruf oder einfach eine Datei sein. Ein direkter Zugriff von außerhalb des Bereichs auf diese Variablen ist ebenfalls nicht möglich.

Das Gegenstück dazu sind die dynamisch gebunden Variablen. Diese werden innerhalb der Namensräume verwaltet. Die Lebensdauer wird von Perl nicht beschränkt so dass man hier auch von globalen Variablen spricht.

Aus diesem Grund und weil bei lexikalischen Variablen der Zugriff ein wenig schneller erfolgt, sollte diese Form den Vorzug erhalten.

Für die globalen Variablen bietet Perl mit dem Schlüsselwort local die Möglichkeit den Wert der Variable auf einen bestimmten Bereich des Programms begrenzt zu verändern. Die Änderung geht beim Verlassen des Bereichs verloren. Das ist der gewünschte Effekt, denn so sind globale Variablen sinnvoller einsetzbar, da sichergestellt ist, dass der ursprüngliche Wert für alle anderen Teile des Programms, wieder hergestellt wird.

Auch wenn in den folgenden Beispielen meist Skalare verwendet werden, gilt das in diesem Kapitel gesagte ebenso für Arrays und Hashes.

Globale Variablen Bearbeiten

Für das Anlegen globaler Variablen gibt es wie üblich in Perl gleich mehrere Möglichkeiten. Die erste und einfachste Variante, die jedoch in der Praxis nicht zu empfehlen ist, besteht darin, das Pragma strict nicht zu verwenden.

package Irgendwie::Irgendwo;

$hier = "Großstadt";

package Irgendwie::Sowieso;

$hier = 'Kuhdorf';

package main;

print "Viele leben in der $Irgendwie::Irgendwo::hier und beneiden die Landeier im $Irgendwie::Sowieso::hier,";

Benutzt man dann eine Variable, so hat man die Variable im Namensbereich des aktuellen package definiert. Der qualifizierte Name der Variablen lautet also $Irgendwie::Irgendwo::hier und $Irgendwie::Sowieso::hier.

use strict "vars";

Jetzt funktioniert das nicht mehr sondern der Variablenname muss vor der Verwendung bekannt gemacht werden. Dafür gibt es auch wieder zwei Wege. Der ältere, den man nutzen sollte, falls es darauf ankommt, dass die Programme auch mit Versionen vor 5.6 laufen, sieht so aus:

use vars qw/$hier $da/;

Mit perl 5.6 wurde das Schlüsselwort our eingeführt, das fast genau denselben Effekt hat.

package Irgendwann;
use strict;

{
    our $zeit;
}

sub verlauf {
    our $zeit;
    ...
}

Normalerweise wird einer Variable bei ihrer Deklaration ein Wert zugewiesen. Entweder explizit im Programm mittels einer Wertzuweisung

our $gestern="heute";

oder implizit durch Perl, nämlich undef für Skalare und die leere Liste bzw. Hash für Listen und Hashes.

our @tage       # entspricht ()
our %sonnentage # ebenso

Existiert eine dynamisch gebundene Variable bereits, wird eine weitere Deklaration mit our, keine implizite Wertzuweisung vornehmen. Das ist sicher auch das Verhalten, welches von einer globalen Variable erwartet werden kann. Man kann so gefahrlos innerhalb einer Funktion (wie in dem Beispiel "verlauf") die Deklaration wiederholen. Sie ist dann nur für alle, die den Programmtext studieren müssen, ein Hinweis darauf, woher diese Variable kommt und dass es sich um eine Paketvariable handelt.

Perlkenner werden es vermuten beziehungsweise wissen, dass es noch andere Möglichkeiten gibt, globale Variablen zu erstellen. Eine ist der ersten vorgestellten Möglichkeit sehr ähnlich und besteht darin, den vollständigen Variablennamen anzugeben. Dieser besteht aus dem Paketnamen und dem eigentlichen Variablennamen.

$Irgendwie::Irgendwo::hier = "ein kleines Dorf";

Diese Variante sollte aber nur dann eingesetzt werden, wenn es keine andere Möglichkeit gibt, da in diesem Fall die Schutzmechanismen, die use strict vor Schreibfehlern bietet, nicht greifen. Nötig ist diese Art, auf eine Variable zuzugreifen, immer dann, wenn von einem anderen Namensraum aus auf eine Variable zugegriffen wird. Außerdem ist bei dieser Form zu beachten, dass zwar die Variable erstellt, aber der Name nicht bekannt gemacht wird. Nur $hier ohne Paketname ist für den Übersetzungsvorgang eine noch nicht deklarierte Variable und würde bei aktiviertem use strict einen Fehler bedeuten.

Das Perl-Standardmodul Exporter bietet eine Möglichkeit, Variablennamen zu exportieren, also den Variablennamen für einen anderen Namensraum nutzbar zu machen. Damit kann eine Variable von mehreren Paketen gemeinsam genutzt werden, ohne immer den vollständigen Paketnamen angeben zu müssen. Es wird dafür im aktuellen Paket ein Alias erzeugt, um auf die Variable zuzugreifen.

Lokale Variablen Bearbeiten

Eine solche Variable hat nur in dem Bereich Gültigkeit in dem sie deklariert wurde. Zu diesem Zweck werden überwiegend lexikalisch gebundene Variablen eingesetzt. Theoretisch könnte man zwar auch mit our eine lokale Variable erstellen. Der Übersetzer beschränkt, ebenso wie bei my die Gültigkeit des Variablennamens auf den aktuellen Block. Am Ende des Blocks müsste die Variable vom Programm aber explizit wieder aus dem Namensraum gelöscht werden. Dieser Aufwand wird nur selten notwendig sein.

Lexikalische Variablen in einem inneren Block überdecken gleichnamige Variablen eines umschließenden Blocks.

Temporäre Wertänderung einer globalen Variable Bearbeiten

Das Schlüsselwort local wird verwendet, um Wertänderungen einer globalen Variablen temporär zu begrenzen. Beim Verlassen des Sichtbarkeitsbereiches wird der alte Wert der Variablen wiederhergestellt. Vor der Einführung von lexikalischen Variablen wurde local oft verwendet. Heutzutage gibt es nur wenige sinnvolle Anwendungen. Haupteinsatzzweck ist die temporäre Änderung von Spezialvariablen.

open my $fh, '<', '/tmp/many_lines.txt';
my $inhalt;
                       # Lesen ist zeilenbasiert
{
  local $/ = undef;    # Lesen ist jetzt nicht mehr zeilenbasiert
  $inhalt = <$fh>;
}
                       # Lesen ist wieder zeilenbasiert, da $/ im obrigen Block lokalisiert war
close $fh;

Äquivalent könnte man obiges auch so implementieren:

open my $fh, '<', '/tmp/many_lines.txt';
my $inhalt;
while (<$fh>) {
    $inhalt .= $_;
}
close $fh;

Siehe auch File::Slurp.