Teil von SELFHTML aktuell Teil von Artikel Teil von CGI/Perl

Coping With Scoping (deutsche Übersetzung)

nach unten Autoren
nach unten Packagevariablen
nach unten Das aktuelle Package
nach unten Wissenswertes über Packagevariablen
nach unten Lexikalische Variablen
nach unten local und my
nach unten Wofür braucht man local?
nach unten Wann verwendet man my und wann local?
nach unten Weitere Eigenschaften von my-Variablen
nach unten Wissenswertes über my-Variablen
nach unten Deklaration
nach unten Zusammenfassung
nach unten Glossar
nach unten Anmerkungen

Autoren

Autor: Mark Jason Dominus

Der englische Originaltext englischsprachige Seite Coping with Scoping wurde im Winter 1998 veröffentlicht. © Copyright 1998 The Perl Journal. Reprinted with permission.

Übersetzer: Torsten Anacker (Siechfred)

E-Mail: E-Mail torsten@anaboe.net

Veröffentlichungsdatum der Übersetzung: 2007-10-26

Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!

nach obennach unten

Coping with Scoping

Am Anfang, irgendwann um 1960 herum, hatte jeder Teil eines Programmes Zugriff auf alle Variablen in allen anderen Bereichen des Programms. Dieses Konzept stellte sich jedoch als problematisch heraus, sodass die Entwickler von Programmiersprachen lokale Variablen einführten, die nur in einem begrenzten Bereich eines Programms sichtbar waren. So konnten Programmierer sicher sein, dass niemand unbefugt Zugriff auf eine Variable x hatte. Daneben konnten sie auch sicher sein, dass es keine Konflikte mit einer Variablen x gibt, die in anderem Kontext an anderer Stelle im Programm verwendet wurde.

Jede Programmiersprache hat ihre eigene Philosophie, und heutzutage ist wesentlicher Bestandteil dieser Philosophie die Art und Weise, wie Variablen verwaltet werden. Kenntnisse darüber, welche Variablen in welchen Bereichen eines Programmes sichtbar sind, welche Bedeutung sie wann und wo haben, sind von immenser Wichtigkeit. Die Ansätze reichen von Barock, wie in Lisp, bis hin zum Hochbarock in C++. Unglücklicherweise befindet Perl sich in dieser Hinsicht irgendwo im frühen Rokoko.

Das Problem von Perl ist, dass es keine klar definierte einheitliche Variablenverwaltung hat, sondern zwei grundverschiedene Systeme, die nebeneinander und gleichzeitig gültig sind. Und das ist das große Geheimnis der Perl-Variablen, das die meisten erst viel zu spät erkennen: Perl hat zwei völlig eigenständige und voneinander unabhängige Variablensätze. Der eine ist ein Relikt aus Perl4-Zeiten, der andere ist neu. Den alten Satz nennt man "Packagevariablen", den neuen "Lexikalische Variablen", und beide haben absolut nichts miteinander zu tun.

Packagevariablen gab es zuerst, weshalb wir uns zunächst mit ihnen beschäftigen. Dabei werden wir die Tücken herausarbeiten, welche Packagevariablen mit sich bringen, und wie lexikalische Variablen, die mit Perl 5 eingeführt wurden, diese Probleme zu beheben versuchen. Schließlich werden wir erfahren, welche Möglichkeiten Perl Ihnen bietet, um automatisch festzustellen, wo und warum Sie nicht die Variablen erhalten, die Sie erwarten, und wie man Fehler finden kann, bevor sie zu Bugs werden.

nach obennach unten

Packagevariablen

$x = 1

Hier ist $x eine Packagevariable. Es gibt zwei Grundregeln, die man über Packagevariablen wissen muss:

  1. Wenn nicht anders deklariert, erhält man immer eine Packagevariable.
  2. Packagevariablen sind stets global.

Global bedeutet, dass Packagevariablen immer und überall in jedem Programm sichtbar sind. Wenn Sie $x = 1 ausgeführt haben, kann jeder andere Teil des Programmes, ja sogar eine Subroutine in einem anderen Script, darauf zugreifen und den Wert von $x verändern. Von diesen Regeln gibt es keine Ausnahme, Packagevariablen sind und bleiben stets global.

Packagevariablen gehören einer bestimmten Familie an, diese nennt man package. Der Name einer jeden Packagevariable besteht aus zwei Teilen. Dies sind der Name der Variablen und der Namen der Familie, zu der sie gehört. Man nennt den Vizepräsidenten der USA auch "Al", doch das ist nur die Kurzform seines vollen Namens "Al Gore". Genauso hat $x einen vollständigen Namen, also zum Beispiel $main::x. Dabei ist "main" der package qualifier, also so wie der Familienname "Gore" des vollständigen Namens "Al Gore". Al Gore und Al Capone sind verschiedene Personen, auch wenn sie den gleichen Vornamen haben. Und genauso sind $Gore::Al und $Capone::Al verschiedene Variablen, ebenso wie $main::x und $DBI::x verschiedene Variablen sind.

Nur wenn Sie den package qualifier angeben, weiß Perl genau, welche Variable gemeint ist. Aber aus Bequemlichkeit könnten Sie den Namen des Packages weglassen wollen. Doch was passiert dann?

nach obennach unten

Das aktuelle Package

Wenn Sie nur $x schreiben, dann nimmt Perl an, dass die Variable $x zum aktuellen Package gehört. Was ist denn nun das aktuelle Package? Normalerweise ist dies main, doch man kann das aktuelle Package wechseln, indem man folgende Anweisung notiert:

package Mypackage;

Von diesem Zeitpunkt an ist Mypackage das aktuelle Package. Die einzige Auswirkung des aktuellen Packages ist die Zuordnung von Packagevariablen, die Sie ohne package qualifier ansprechen. Wenn Mypackage das aktuelle Package ist, dann bedeutet $x in ausführlicher und vollständiger Schreibweise $Mypackage::x. Ist main das aktuelle Package, dann bezieht sich $x tatsächlich auf $main::x.

Wenn Sie ein Modul schreiben wollen, als Beispiel MyModule, werden Sie wahrscheinlich als erste Anweisung der Moduldatei Folgendes schreiben:

package MyModule;

Von da an gehören alle Packagevariablen, die Sie in der Moduldatei verwenden, zum Package MyModule, und Sie können ziemlich sicher sein, dass es zwischen diesen Variablen und den anderen Variablen im restlichen Programm keine Konflikte geben wird. Es spielt keine Rolle, ob Sie und der Autor des DBI-Moduls eine Variable $x verwenden, weil die eine Variable $MyModule::x und die andere $DBI::x wäre.

Erinnern Sie sich: Packagevariablen sind immer global. Egal, ob Sie sich im Package DBI befinden oder nicht, egal ob Sie jemals vom Package DBI gehört haben, nichts kann Sie daran hindern, $DBI::errstr zu lesen oder zu schreiben. Sie müssen nichts Spezielles tun. $DBI::errstr ist, wie alle Packagevariablen, eine globale Variable, und sie ist global verfügbar, alles, was Sie tun müssen, ist, sie mit ihrem vollen Namen anzusprechen. Sie können sogar Folgendes machen:

package DBI;
$errstr = 'Ha ha Tim!';

und das würde $DBI::errstr ändern.

nach obennach unten

Wissenswertes über Packagevariablen

Es gibt drei Dinge, die man über Packagevariablen wissen sollte, wenngleich Sie diesen Abschnitt beim ersten Lesen getrost überspringen können:

  1. Ein leerer Packagename ist das Gleiche wie main. Deshalb ist $::x dasselbe wie $main::x für alle x.
  2. Manche Variablen dürfen nur im Package main vorkommen. Bei %ENV zum Beispiel wird Perl immer %main::ENV annehmen, selbst wenn das aktuelle Package nicht main ist. Wenn Sie %Fred::ENV ansprechen wollen, müssen Sie das ausdrücklich so angeben, selbst wenn Fred das aktuelle Package ist. Andere Symbole, für die das Gleiche gilt, sind INC, alle vordefinierten Variablen wie $_ oder $$ und @ARGV sowie STDIN, STDOUT und STDERR.
  3. Packagenamen können auch zwei Doppelpunkte (::) enthalten. So kann es eine Variable $DBD::Oracle::x geben, welche die Variable x im Package DBD::Oracle meint, aber nichts mit dem Package DBD zu tun hat. Isaac Newton ist nicht mit Olivia Newton-John verwandt, und Newton::Isaac ist nicht verwandt mit Newton::John::Olivia, obwohl beide mit Newton beginnen. Newton::John::Olivia gehört zum Package Newton::John, nicht zum Package Newton.

Das ist eigentlich schon alles, was man über Packagevariablen noch wissen sollte.

Packagevariablen sind global, was potenziell gefährlich ist, da man nie sicher sein kann, dass irgendjemand anderes sie hinter Ihrem Rücken manipuliert. Bis einschließlich Perl 4 waren alle Variablen Packagevariablen, was mit Risiken verbunden war. Deshalb wurden mit Perl 5 ein neuer Satz von nicht globalen Variablen eingeführt.

nach obennach unten

Lexikalische Variablen

Der zweite Variablensatz in Perl sind die lexikalischen Variablen (warum sie so heißen, wird später noch erklärt) oder auch privaten Variablen, weil sie tatsächlich privat sind. Zuweilen nennt man sie auch my-Variablen, da sie stets mit my deklariert werden. Es erscheint verlockend, sie lokale Variablen zu nennen, weil sich ihr Gültigkeitsbereich nur auf einen bestimmten klar abgegrenzten Bereich des Programmes erstreckt. Doch das sollte man vermeiden, denn sonst könnte man denken, dass Sie den local-Operator meinen, den wir später betrachten werden. Wenn Sie also eine lokale Variable deklarieren möchten, dann denken Sie zuerst an my, nicht an local.

Die Deklaration

my $x;

erzeugt eine neue Variable mit dem Namen x, die in den meisten Teilen des Programms nicht sichtbar ist, nämlich überall außerhalb des Blocks, in dem die Variable deklariert wurde. Diesen Block nennt man den Scope [A.d.Ü.: Gültigkeitsbereich] der Variable. Wenn die Variable nicht innerhalb eines Blocks deklariert wurde, ist sie vom Zeitpunkt der Deklaration bis zum Ende der Scriptdatei gültig.

Sie können eine my-Variable zugleich deklarieren und initialisieren, indem Sie schreiben:

my $x = 119;

Sie können auch mehrere auf einmal deklarieren und initialisieren:

my ($x, $y, $z, @args) = (5, 23, @_);

Lassen Sie uns an einem Beispiel demonstrieren, wann private Variablen nützlich sind. Angenommen, wir haben folgende Subroutine:

sub print_report {
  @employee_list = @_;
  foreach $employee (@employee_list) {
    $salary = lookup_salary($employee);
    print_partial_report($employee, $salary);
  }
}

Wenn lookup_salary zufällig ebenfalls eine Variable namens $employee nutzt, ist dies die selbe Variable, die auch in print_report genutzt wird, sie kleben förmlich aneinander. Die zwei Programmierer, die für print_report und lookup_salary verantwortlich sind, müssen sich absprechen um sicherzugehen, dass sie nicht die gleichen Variablennamen verwenden. Das nervt und ist selbst in kleinen und mittleren Projekten nicht hinnehmbar.

Die Lösung: Verwenden Sie my-Variablen:

sub print_report {
  my @employee_list = @_;
  foreach my $employee (@employee_list) {
    my $salary = lookup_salary($employee);
    print_partial_report($employee, $salary);
  }
}

my @employee_list erzeugt ein neues Array, auf das außerhalb der Subroutine print_report niemand weiter Zugriff hat. for my $employee erzeugt einen neuen Skalar, auf den man außerhalb des foreach-Loops nicht zugreifen kann, so wie es innerhalb des Loops my $salary tut. Sie müssen sich also keine Gedanken darüber machen, ob andere Funktionen des Programms auf diese Variablen zugreifen und sie verändern, weil sie es schlicht nicht können; sie wissen gar nicht, wie sie diese Variablen ansprechen sollen, weil die Variablennamen außerhalb des Gültigkeitsbereichs der my-Variablen eine andere Bedeutung haben. Diese my-Variablen werden deshalb auch lexikalische Variablen genannt, weil sich ihr Gültigkeitsbereich ausschließlich nach dem Text des Programmcodes richtet, und nicht danach, was wann ausgeführt wird. Sie können den Gültigkeitsbereich durch bloßes Lesen des Programmcodes erkennen, ohne genau zu wissen, was der Code tut. Wann immer Ihnen eine Variable begegnet, suchen Sie nach einer my-Deklaration weiter oben im gleichen Block. Wenn Sie eine finden, können Sie sicher sein, dass auf diese Variable außerhalb des Blocks nicht zugegriffen werden kann. Wenn Sie keine my-Deklaration im selben Block finden, dann schauen Sie im nächsthöheren Block - also in dem Block, der Ihren aktuellen Block umschließt - nach und so weiter, bis Sie eine my-Deklaration gefunden haben. Erst, wenn Sie trotzdem keine my-Deklaration finden konnten, ist die Variable eine Packagevariable.

my-Variablen sind keine Packagevariablen. Sie sind weder Teil eines Packages, noch haben sie einen package qualifier. Das aktuelle Package hat keinen Einfluss darauf, wie diese Variablen interpretiert werden. Hier ist ein Beispiel:

my $x = 17;

package A;
$x = 12;

package B;
$x = 20;

# $x ist nun 20.
# $A::x und $B::x sind undefined

Die Deklaration my $x = 17 am Anfang erzeugt eine neue lexikalische Variable namens x, deren Gültigkeit sich bis zum Ende der Scriptdatei erstreckt. Diese neue Bedeutung von $x ändert das bisher beschriebene Standardverhalten, nach dem $x eine Packagevariable des aktuellen Packages wäre.

package A wechselt das aktuelle Package, aber weil $x als lexikalische Variable deklariert wurde und nicht als Packagevariable, hat $x = 12 keinerlei Auswirkungen auf $A::x. Genauso modifiziert $x = 20 die lexikalische Variable, nicht aber irgendeine Packagevariable.

Am Ende des Scripts hat die lexikalische Variable $x den Wert 20, und die Packagevariablen $main::x, $A::x und $B::x sind nachwievor nicht deklariert. Hätten Sie diese deklarieren wollen, hätten Sie sie mit ihrem vollständigen Namen ansprechen müssen.

Folgende Grundsätze sollten Ihnen nun klar sein:

nach obennach unten

local und my

Nahezu jeder weiß, dass es eine local-Funktion gibt, die irgendetwas mit lokalen Variablen zu tun hat. Doch was bedeutet das und was ist der Unterschied zu my? Die Antwort ist ebenso einfach wie überraschend:

my erzeugt eine lokale Variable, local nicht.

Was local $x bewirkt, ist Folgendes: Es speichert den aktuellen Wert der Packagevariable $x an einem sicheren Ort, und ersetzt ihn mit einem neuen Wert bzw. mit undef, wenn kein neuer Wert angegeben wurde. Es sorgt ebenfalls dafür, dass der alte Wert wieder hergestellt wird, wenn die Ausführung des aktuellen Blocks beendet ist. Die betroffenen Variablen sind Packagevariablen, die lediglich vorübergehend einen anderen lokalen Wert erhalten. Doch trotzdem bleiben diese Packagevariablen immer globale Variablen, daran ändert auch local nichts. Um den Unterschied zu erkennen, versuchen Sie Folgendes:

$lo = 'global';
$m  = 'global';
A();

sub A {
  local $lo = 'AAA';
  my    $m  = 'AAA';
  B();
}

sub B {
  print "B ", ($lo eq 'AAA' ? 'kann ' : 'kann nicht') ,
                " auf den Wert von lo zugreifen, der von A gesetzt wurde.\n";
  print "B ", ($m  eq 'AAA' ? 'kann' : 'kann nicht') ,
                " auf den Wert von m zugreifen, der von A gesetzt wurde.\n";
}

Das gibt Folgendes aus:

B kann auf den Wert von lo zugreifen, der von A gesetzt wurde.
B kann nicht auf den Wert von m zugreifen, der von A gesetzt wurde.

Was geschieht hier? Die local-Anweisung in A weist der Packagevariablen $lo einen neuen temporären Wert AAA zu. Der alte Wert global wird wiederhergestellt, wenn die Ausführung von A beendet ist, doch zuvor ruft A die Funktion B auf. B hat kein Problem, auf $lo zuzugreifen, da es sich um eine Packagevariable handelt, die immer und überall verfügbar sind. Deshalb sieht B den Wert AAA, der von A gesetzt wurde.

Im Gegensatz dazu erzeugt my eine neue lexikalische Variable namens $m, die nur innerhalb der Funktion A sichtbar ist. Außerhalb von A erhält $m seine ursprüngliche Funktion als Packagevariable $m zurück, die nachwievor den Wert global hat. Das ist die Variable, die B sieht. Es sieht nichts von AAA, weil die Variable mit diesem Wert eine lexikalische Variable ist, die nur innerhalb von A existiert.

nach obennach unten

Wofür braucht man local?

Weil local keine lokale Variable erzeugt, wird es nicht sehr oft verwendet. Wenn im obigen Beispiel B den Wert von $lo modifizieren würde, dann würde der Wert, den A der Variablen zugewiesen hat, überschrieben werden. Doch genau das wollen wir nicht. Wir wollen, dass jede Funktion ihre eigenen Variablen hat, die von den anderen nicht angetastet werden kann. Das ist genau das, was my tut.

Warum gibt es dann local? Die Antwort liegt zu 90% in der Historie von Perl. Frühere Versionen kannten nur globale Variablen. local war einfach zu implementieren und wurde mit Perl 4 eingeführt, um das Problem mit lokalen Variablen wenigstens teilweise zu lösen. Mit Perl 5 machte man sich mehr Arbeit und führte echte lokale Variablen ein. Doch der Begriff local war schon vergeben, sodass das neue Feature mit dem Schlüsselwort my verbunden wurde. my wurde gewählt, weil es Privatsphäre suggeriert, aber auch, weil es sehr kurz ist; die Kürze soll Sie dazu animieren, es an Stelle von local zu verwenden. Darüber hinaus ist my schneller als local.

nach obennach unten

Wann verwendet man my und wann local?

Verwenden Sie stets my; niemals local.

Ganz einfach, oder?

nach obennach unten

Weitere Eigenschaften von my-Variablen

Immer, wenn eine my-Deklaration gefunden wird, erzeugt Perl eine neue, frische Variable. Folgender Code beispielsweise gibt fünfzigmal x=1 aus:

for (1 .. 50) {
  my $x;
  $x++;
  print "x=$x\n";
}

Man erhält bei jedem Durchlauf eine neue Variable $x, die zunächst keinen definierten Wert hat. Wäre die Deklaration außerhalb des Loops, würde nur einmal eine Variable angelegt werden:

{ my $x;
  for (1 .. 50) {
    $x++;
    print "x=$x\n";
  }
}

Dies gibt aus: x=1, x=2, x=3, ... x=50.

Das können Sie für einen nützlichen Trick verwenden. Angenommen, Sie haben eine Funktion, die sich einen Wert von einem Aufruf bis zum nächsten merken muss, z.B. ein Zufallsgenerator. Ein typischer Zufallsgenerator (wie auch die rand-Funktion von Perl) verwendet ein so genanntes seed. Dabei handelt es sich einfach nur um eine Zahl. Wenn man den Zufallsgenerator nach einer Zufallszahl fragt, führt die Funktion ein paar Rechenoperationen aus, welche das seed durcheinanderwürfeln, und gibt das Ergebnis zurück. Gleichzeitig merkt sie sich das Ergebnis und verwendet es als seed für den nächsten Aufruf.

Hier ein typisches Beispiel (aus dem ANSI-C-Standard, aber es ist nicht wirklich brauchbar, deshalb verwenden Sie es nicht für etwas Wichtiges):

$seed = 1;
sub my_rand {
  $seed = int(($seed * 1103515245 + 12345) / 65536) % 32768;
  return $seed;
}

Eine typische Ausgabe sähe so aus:

16838
14666
10953
11665
 7451
26316
27974
27550

Hier gibt es ein Problem, da $seed eine globale Variable ist, weshalb wir dafür Sorge tragen müssen, dass niemand unabsichtlich ihren Wert verändert. Oder die Variable wird absichtlich verändert, um den Programmablauf zu beeinflussen. Was wäre, wenn die Funktion in einem Spieleprogramm verwendet werden würde, und irgendjemand manipuliert den Zufallsgenerator?

Aber wir können $seed nicht als my-Variable innerhalb der Funktion deklarieren:

sub my_rand {
  my $seed;
  $seed = int(($seed * 1103515245 + 12345) / 65536) % 32768;
  return $seed;
}

Würden wir das tun, würde $seed bei jedem Aufruf von my_rand neu deklariert und mit einem nicht definierten Wert initialisiert werden. Wir wollen aber, dass der Wert zwischen zwei Aufrufen von my_rand erhalten bleibt.

Und hier ist die Lösung:

{ my $seed = 1;
  sub my_rand {
    $seed = int(($seed * 1103515245 + 12345) / 65536) % 32768;
    return $seed;
  }
}

Die Deklaration erfolgt außerhalb der Funktion, sodass sie nur einmal ausgeführt wird, nämlich dann, wenn das Programm kompiliert wird, aber nicht jedesmal, wenn die Funktion aufgerufen wird. Denn es ist eine my-Variable, die in einem Block eingeschlossen ist, in dem es außer ihr nur noch my_rand gibt, sodass $seed nur für die Funktion my_rand sichtbar ist.

$seed wird auch als statische Variable bezeichnet, weil sie zwischen den Funktionsaufrufen ihren Wert beibehält (Und weil es in C ein ähnliches Feature gibt, das durch das static-Schlüsselwort aktiviert wird).

nach obennach unten

Wissenswertes über my-Variablen

  1. Sie können keine my-Variablen anlegen, deren Namen nicht mit einem Buchstaben beginnt, so wie $_, @_ oder $$. Sie können die vordefinierten Variablen $1, $2 usw. nicht mit my deklarieren. Die Erfinder von my glaubten wohl, das wäre zu verwirrend.
  2. Sie können nicht schreiben my $DBI::errstr, weil das widersprüchlich ist - es würde bedeuten, dass die Packagevariable $DBI::errstr nun eine lexikalische Variable ist. Sie können aber local $DBI::errstr verwenden; dies speichert den aktuellen Wert von $DBI::errstr und sorgt dafür, dass er am Ende des Blocks wiederhergestellt wird.
  3. Seit Perl 5.004 kann man

    foreach my $i (@list) {

    schreiben, um die Gültigkeit von $i auf den Loop zu begrenzen. Genauso begrenzt

    for (my $i=0; $i<100; $i++) {

    die Gültigkeit von $i auf den for-Loop.

nach obennach unten

Deklaration

Wenn Sie eine Funktion schreiben, die eine private Variable haben soll, müssen Sie diese Variable mit my deklarieren. Doch was passiert, wenn Sie es vergessen?

sub function {
  $x = 42;        # Ups, das sollte my $x = 42 lauten.
}

In diesem Falle modifiziert die Funktion die globale Packagevariable $x. Wenn Sie diese Variable bereits für etwas anderes verwendet haben, kann das eine Katastrophe für Ihr Programm bedeuten.

Aktuelle Perl-Versionen haben einen optionalen Schutz dagegen, den Sie verwenden können. Wenn Sie

use strict 'vars';

am Anfang Ihres Programmes notieren, verlangt Perl, dass Packagevariablen einen expliziten package qualifier enthalten. $x = 42 hat keinen solchen qualifier, das Programm würde nicht kompiliert werden; stattdessen bricht der Compiler mit einer Fehlermeldung ab:

Global symbol "$x" requires explicit package name at ...

Wenn Sie $x als private my-Variable deklarieren wollen, dann fügen Sie my hinzu. Wenn Sie dagegen wirklich eine globale Packagevariable nutzen möchten, dann ändern Sie die Anweisung wie folgt:

$main::x = 42;

oder welches Package auch immer das aktuell verwendete ist.

Wenn Sie nur use strict schreiben, werden neben strict vars verschiedene weitere Tests aktiviert. Lesen Sie englischsprachige Seite perldoc strict für weitere Details.

Angenommen, Sie schreiben ein Modul Algorithms::KnuthBendix, und Sie möchten strict vars verwenden. Aber Sie fürchten, dass Sie das Modul nie fertigstellen werden, weil Ihre Finger vom ständigen Tippen von $Algorithms::KnuthBendix::Error irgendwann abfallen.

Sie können Ihre Finger retten und strict vars mitteilen, dass es eine Ausnahme machen soll:

package Algorithms::KnuthBendix;
use vars '$Error';

Dies verhindert für die Packagevariable $Algorithms::KnuthBendix::Error, dass strict vars einen Fehler meldet, wenn Sie die Kurzschreibweise $Error verwenden.

Sie können strict vars auch für einen bestimmten Block ausschalten, indem Sie schreiben:

{ no strict 'vars';

  # strict vars ist ab hier für diesen Block abgeschaltet.

}

nach obennach unten

Zusammenfassung

Packagevariablen sind immer global und bestehen aus dem package qualifier gefolgt von ihrem Namen. Man kann den package qualifier weglassen, dann benutzt Perl den Standard [A.d.Ü.: in Gestalt des aktuellen Packages], den Sie durch die package-Anweisung ändern können. Für private Variablen benutzen Sie my. Verwenden Sie local nicht, es ist überflüssig.

Sie sollten globale Variablen vermeiden, weil es sehr schwer ist zu verhindern, dass zwei Teile eines Programmes versehentlich den gleichen Variablennamen benutzen.

Um den ungewollten Einsatz globaler Variablen zu verhindern, benutzen Sie use strict 'vars'. Es prüft und stellt sicher, dass alle Variablen entweder als privat deklariert sind, einen package qualifier enthalten oder explizit mit use vars deklariert wurden [A.d.Ü.: Siehe auch unten Anmerkung 3].

nach obennach unten

Glossar

nach obennach unten

Anmerkungen

  1. Die technischen Redakteure haben sich über meinen Grundsatz, niemals local zu nutzen, beschwert. Doch in 97% aller Fälle trifft dieser Grundsatz zu. local hat einige wenige Anwendungsbereiche, die allerdings nicht sehr oft vorkommen, weshalb ich sie nicht erwähnt habe. Der Anspruch eines Tutorials ist nunmal, 97% der Informationen in 50% des eigentlich nötigen Platzes darzustellen. Ich habe befürchtet, dass ich einen Haufen E-Mails der Art "Du hast vergessen zu erwähnen, dass local für dieses oder jenes verwendet werden kann." bekomme. Deshalb habe ich das Erscheinen eines weiteren Artikels englischsprachige Seite Sieben sinnvolle Anwendungen von local in drei Monaten angekündigt, damit mich die Leute mit local in Ruhe lassen, und der Artikel ist erschienen, wenn auch etwas später.

    englischsprachige Seite Sieben sinnvolle Anwendungen für local ist nun auf der Webseite verfügbar. Es wurde in The Perl Journal Ausgabe 14 veröffentlicht.

  2. Hier ist ein weiterer interessanter Aspekt, den ich aus Platz- und Verständnisgründen nicht erwähnt habe. Robert Watkins schickte mir eine E-Mail mit einem von ihm geschriebenen Programm, das nicht lief. Der "Bug" ließ sich auf folgenden Code reduzieren:

    my $x;
    
    for $x (1..5) {
      t();
    }
    
    sub t { print "$x, " }

    Robert erwartete eine Ausgabe der Art 1, 2, 3, 4, 5, doch stattdessen erhielt er , , , , , . Wo war der Wert von $x hin?

    Der Grund ist Folgender: Wenn man schreibt:

    for $x (...) { }

    wird Perl den Wert der Indexvariable auf den Loop beschränken. Wenn $x eine Packagevariable ist, erwartet Perl allerdings, dass Sie folgendes schreiben:

    { local $x; for $x (...) { } }

    Wenn $x eine lexikalische Variable ist, erwartet es, dass Sie stattdessen Folgendes schreiben:

    { my $x;    for $x (...) { } }

    Das bedeutet aber, dass die Indexvariable nicht an Subroutinen weitergegeben wird, selbst wenn sich diese im selben Scope wie der Loop befinden.

    Aber vielleicht hätte ich es gar nicht so ausführlich schreiben müssen, denn englischsprachige Seite perlsyn beschreibt es recht einleuchtend:

    ... Die Variable ist ausdrücklich lokal innerhalb des Loops und erhält ihren früheren Wert zurück, wenn der Loop verlassen wird. Wenn die Variable zuvor mit my deklariert wurde, wird diese [A.d.Ü.: lexikalische] Variable statt der globalen genutzt, trotzdem ist sie im Loop lokal. (Beachten Sie, dass lexikalische Variablen Probleme verursachen können, wenn Sie Subroutinen oder Formatdeklarationen innerhalb des Loops haben, die darauf verweisen.)

    Meiner Meinung nach war der Fehler, die Indexvariable als lexikalisch zu deklarieren. Wenn Sie das gewollt hätten, hätten Sie for my $x ... schreiben müssen. Ich habe versucht, die lexikalische Variable zu lokalisieren: Der Wert der lexikalischen Variable sollte vor dem Loop gesichert und danach wiederhergestellt werden. Doch es scheint technische Gründe zu geben, dass man das so nicht machen kann, weil es nicht funktioniert:

    my $m;
    { local $m = 12;
      ...
    }

    Die local-Anweisung scheitert mit der Fehlermeldung:

    Can't localize lexical variable $m...

    In der Perl5-Porters-Mailingliste wurde schon darüber gesprochen, es zu ermöglichen, es scheint aber nicht so einfach zu sein.

  3. Hinzugefügt 2000-01-05: Mit Perl 5.6.0 wurde eine neue our-Deklaration eingeführt. Die Syntax entspricht der von my und ersetzt use vars.

    Ohne weiter ins Detail zu gehen, ist our eigentlich das Gleiche wie use vars; der einzige Zweck ist es, Variablen zu deklarieren, die von strict vars nicht überprüft werden. Allerdings gibt es zwei Vorteile gegenüber use vars: Die Syntax ist weniger verwirrend und der Scope ist lexikalisch. Das bedeutet, dass die Ausnahme von der strict-Prüfung nur bis zum Ende des aktuellen Blocks gilt:

    use strict 'vars';
    {
      our $x;
      $x = 1;   # Der Gebrauch der globalen Variablen $x ist ok.
    }
    $x = 2;     # Der Zugriff auf $x ergibt wie erwartet einen Fehler

    Während also use vars '$x' bedeutet, dass die globale Variable $x überall benutzt werden kann, erlaubt our $x, den Gültigkeitsbereich auf bestimmte Programmbereiche einzuschränken und ergibt einen Fehler, wenn Sie versehentlich versuchen, außerhalb dieses Bereiches darauf zugreifen.

  4. Hinzugefügt 2000-01-05: Hier ist eine kleine Besonderheit, die möglicherweise überrascht. Nehmen wir folgendes Programm:

    use strict 'vars';
    my @lines = <>;
    my @sorted = sort backwards @lines;
    print @sorted;
    
    sub backwards { $b cmp $a }

    $a und $b sind nirgendwo deklariert, deshalb sind sie globale Variablen. Das müssen sie auch sein, weil der sort-Operator in der Lage sein muss, ihren Wert zu ändern und ihn der backwards-Funktion zur Verfügung zu stellen. Warum gibt es dann unter strict keinen Fehler?

    Die Variablen $a und $b sind genau aus diesem Grund von strict ausgenommen [A.d.Ü.: Und sollten deshalb nie als eigene Variablen benutzt werden].

Teil von SELFHTML aktuell Teil von Artikel Teil von CGI/Perl

© 2007 bereichsübergreifende Seite Impressum, für diese Seite: E-Mail torsten@anaboe.net