Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
am 01.09.2006 19:20:54 von Torsten Mohr
Hallo,
ich suche Informationen darüber, was beim Einlesen eines
Skriptes passiert.
Die Info in "perlmod" war ganz hilfreich, z.B. daà die
BEGIN() in einer String-eval-Umgebung ausgeführt wird.
Eine Frage zu "use", das ist ja äquivalent zu einem
BEGIN-Block mit require und import() darin. Â HeiÃt das
daà das "use" genauso wie ein BEGIN() noch während des
Kompilierens ausgeführt wird?
Das würde ja auch bedeuten daà es auf die Reihenfolge
des Auftretens ausgewertet werden, richtig (das würde sich
mit meinen Beobachtungen treffen)?
Ein explizites Aufrufen von BEGIN() oder END() im Skript
funktioniert nicht, das konnte ich der Doku so nicht
entnehmen.  Hab ich was überlesen?
Wenn ich innerhalb eines END-Blockes ein "use" stehen habe
wird das ebenfalls direkt nach dem Einlesen des Skriptes
ausgeführt, trotzdem es im END-Block steht. Ist das
irgendwo beschrieben, so daà man das Verhalten allgemein
beschreiben kann, ohne jeden Fall auszuprobieren?
Kann mir jemand einen Tip geben an welcher Stelle ich
mehr zu diesem Themenbereich lesen kann?
GrüÃe,
Torsten.
Re: Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
am 01.09.2006 23:42:55 von hjp-usenet2
On 2006-09-01 17:20, Torsten Mohr wrote:
> Die Info in "perlmod" war ganz hilfreich, z.B. daà die
> BEGIN() in einer String-eval-Umgebung ausgeführt wird.
^^ Warum schreibst Du hier runde Klammern? Ein BEGIN-Block ist
keine Subroutine.
> Eine Frage zu "use", das ist ja äquivalent zu einem
> BEGIN-Block mit require und import() darin. Â HeiÃt das
> daà das "use" genauso wie ein BEGIN() noch während des
> Kompilierens ausgeführt wird?
Ja.
> Das würde ja auch bedeuten daà es auf die Reihenfolge
> des Auftretens ausgewertet werden, richtig (das würde sich
> mit meinen Beobachtungen treffen)?
Da sind Dir irgendwie zwei Sätze ineinandergerutscht. Ja, es kommt auf
die Reihenfolge an, und ja, "use" und "BEGIN" werden in der Reihenfolge
ihres Auftretens ausgewertet.
> Ein explizites Aufrufen von BEGIN() oder END() im Skript
> funktioniert nicht, das konnte ich der Doku so nicht
> entnehmen.  Hab ich was überlesen?
Ja:
One should note that these code blocks donât really exist as named
subroutines (despite their appearance). The thing that gives this
away is the fact that you can have more than one of these code
blocks in a program, and they will get all executed at the
appropriate moment. So you canât execute any of these code blocks
by name.
> Wenn ich innerhalb eines END-Blockes ein "use" stehen habe
> wird das ebenfalls direkt nach dem Einlesen des Skriptes
> ausgeführt,
Nicht nach dem Einlesen, sondern während des Einlesens, nämlich
unmittelbar nachdem das Statement geparst wurde.
> trotzdem es im END-Block steht. Ist das irgendwo beschrieben, so daÃ
> man das Verhalten allgemein beschreiben kann, ohne jeden Fall
> auszuprobieren?
Das folgt IMHO daraus, dass use äquivalent zu einem BEGIN-Block ist.
Ich sehe nirgends eine beschrieben, dass das innerhalb von END-Blöcken
anders sein sollte.
hp
--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp@hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
Re: Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
am 03.09.2006 09:30:54 von Torsten Mohr
Hallo,
danke für deine Tips.
>> Ein explizites Aufrufen von BEGIN() oder END() im Skript
>> funktioniert nicht, das konnte ich der Doku so nicht
>> entnehmen.  Hab ich was überlesen?
>
> Ja:
>
> One should note that these code blocks donât really exist as named
> subroutines (despite their appearance). The thing that gives this
> away is the fact that you can have more than one of these code
> blocks in a program, and they will get all executed at the
> appropriate moment. So you canât execute any of these code blocks
> by name.
Tatsächlich, das hab ich übersehen.
GrüÃe,
Torsten.
Re: Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
am 04.09.2006 18:07:24 von Ferry Bolhar
Torsten Mohr:
> Eine Frage zu "use", das ist ja äquivalent zu einem
> BEGIN-Block mit require und import() darin. Heißt das
> daß das "use" genauso wie ein BEGIN() noch während des
> Kompilierens ausgeführt wird?
Ja. Darin liegt ja der Sinn von "use", dass es Perl- (und XS-Code)
die Möglichkeit gibt, in den Compilierungsprozess einzugreifen
und das im Entstehen befindliche Programm zu modifizieren. Das
gilt sinngemäß übrigens auch für CHECK-Blöcke.
"use" ist kein zur Laufzeit ausgeführter Befehl (wie zB. "print"),
sondern es ist eine Art "Compilerdirektive" (wie "package" oder
"my"/"our"). Stößt der Parser beim Einlesen des Skripts auf ein
"use", führt er das sofort durch. Das führt manchmal zu Miss-
verständnissen in Code wie
if ($use_a == 1) {
use a;
print "Nur a wurde geladen!";
} else {
use b;
print "Nur b wurde geladen!";
}
Dieser Code macht nicht das, nach dem er aussieht, sondern:
BEGIN {
require a;
a->import();
require b;
b->import();
}
if ($use_a == 1) {
print "Nur a wurde geladen!\n";
} else {
print "Nur b wurde geladen!\n";
}
d.h, es werden zuerst _beide_ Module geladen und erst viel später,
zur Laufzeit, wird die if-Bedingung geprüft und der jeweilige (aber
hier in keinem Fall inhaltlich richtige) Text wird ausgegeben.
Wenn du C kennst, ist es hilfreich, "use" mit der "#include" Direktive
zu vergleichen. Stell dir den C-Code
if (use_a == 1)
{
# include
printf("Nur a wurde geladen!\n");
}
else
{
# include
printf("Nur b wurde geladen!\n");
}
vor - da wird transparenter, was wann passiert. In Perl sind die
Unterschiede zwischen Compilerdirektiven und Laufzeitbefehlen
leider nicht so klar abgegrenzt - wohl auch deswegen, weil manche
Konstrukte (zB "sub") sowohl für das eine als auch für das andere
verwendet werden können.
> Das würde ja auch bedeuten daß es auf die Reihenfolge
> des Auftretens ausgewertet werden, richtig (das würde sich
> mit meinen Beobachtungen treffen)?
Es kommt klarerweise auf die Reihenfolge des Auftretens an. Bei
einem
use a;
BEGIN {
print "BEGIN";
}
use b;
wird zuerst das Skript a.pm geladen und ausgeführt, dann der BEGIN-
Block und danach wird b.pm geladen (wobei hier dann auch noch die
import-Funktionen, so vorhanden, aufgerufen werden, siehe oben).
> Ein explizites Aufrufen von BEGIN() oder END() im Skript
> funktioniert nicht, das konnte ich der Doku so nicht
> entnehmen.
BEGIN und END sind - wie auch CHECK und INIT - reservierte
Namen. Stößt der Parser auf einen solchen Namen, so registriert er
den damit gekennzeichneten Codeblock auf spezielle Art und Weise,
und nicht wie jede andere Subroutine in Form eine Code-Referenz
auf einen Typeglob.
Solche Blöcke sind daher im Skript nicht direkt sicht- und somit auch
nicht explizit aufrufbar. Das geht auch schon deswegen nicht, weil es
ja mehrere dieser Blöcke geben kann und daher ein
&BEGIN;
dann nicht mehr eindeutig wäre.
> Hab ich was überlesen?
Ich würde sagen, ja. Diese Blöcke sind in perlmod beschrieben;
suche nach "BEGIN, CHECK, INIT and END".
> Wenn ich innerhalb eines END-Blockes ein "use" stehen habe
> wird das ebenfalls direkt nach dem Einlesen des Skriptes
> ausgeführt, trotzdem es im END-Block steht. Ist das
> irgendwo beschrieben, so daß man das Verhalten allgemein
> beschreiben kann, ohne jeden Fall auszuprobieren?
Für BEGIN-Blöcke gilt sinngemäß dasselbe wie für "use" - ein
solcher Block wird ausgeführt, sobald er zur Gänze kompiliert wurde,
unabhängig vom Kontext zur Laufzeit. Wenn du also schreibst:
END {
print "Ende 1";
BEGIN {
print "Begin!";
}
print "Ende 2";
}
wird daraus:
BEGIN {
print "Begin!";
}
END {
print "Ende 1";
print "Ende 2";
}
Also:
1) Der Parser stößt auf das reserviert Wort END und beginn mit dem
Compilieren des END-Blocks.
2) Der Parser stößt auf das reservierte Wort BEGIN, setzt das Compilieren
des END-Blocks aus und beginnt mit dem Compilieren des BEGIN-Blocks.
3) Sobald der BEGIN-Block fertig compiliert ist, wird er ausgeführt.
Anschließend wird der BEGIN-Code entfernt.
4) Der Compiler macht mit dem END-Block weiter und registriert diesen,
sobald das Compilieren des Blocks abgeschlossen ist, als END-Block für
die spätere Ausführung.
Es kann helfen, sich auch BEGIN und END als Compilerdirektiven
"Mach das Folgende sofort/so spät wie möglich" vorzustellen.
> Kann mir jemand einen Tip geben an welcher Stelle ich
> mehr zu diesem Themenbereich lesen kann?
Kommt darauf an, was du wissen willst. Eine recht interessante
Abhandlung über Dinge, die man in BEGIN und CHECK-Blöcken
machen kann, findet sich in "Advanced Perl Programming, 2nd
Edition" von Simon Cozens (O'Reilly 2005, ISBN 0-596-00456-7).
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
am 07.09.2006 21:16:35 von Torsten Mohr
Hallo,
vielen Dank für die ausführliche Erklärung! Das hat mir sehr
weitergeholfen.
Viele GrüÃe,
Torsten.
Re: Ablauf beim Starten eines Skriptes, BEGIN(), use, ...
am 08.09.2006 17:53:48 von Ferry Bolhar
Ich schrieb:
> Dieser Code macht nicht das, nach dem er aussieht, sondern:
>
> BEGIN {
> require a;
> a->import();
> require b;
> b->import();
> }
Genauer müsste es heißen:
BEGIN {
require a;
a->import() if a->can('import');
require b;
b->import() if b->can('import');
}
da es natürlich Module geben kann, die zwar mit "use" geladen werden,
aber keine import()-Methode zur Verfügung stellen (und auch nicht erben).
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at