Allmählich nähert sich dieses Buch seinem Ende, und Sie haben sich mit den meisten Aspekten von Perl bereits vertraut gemacht oder zumindest hineingeschnuppert. Doch mit welchem Thema man sich auch beschäftigt, immer bietet Perl alternative Möglichkeiten und weitere Lösungswege, die ich aus Platzgründen nicht alle beschreiben konnte.
Betrachten Sie deshalb dieses Kapitel als Vertiefung zum ganzen Buch. Wir werden heute eine Reihe von Themen erörtern, die ich bisher nicht angesprochen habe, weil sie entweder zu komplex oder von zu peripherer Bedeutung für die einzelnen Kapitelinhalte waren. Diese Themen umfassen:
Wenn Sie ein Perl-Skript schreiben, wird Ihre Vorgehensweise meistens so aussehen, wie bisher in diesem Buch beschrieben: Sie schreiben das Skript, speichern es in einer Datei und bedienen sich dann des Perl-Interpreters, um das Skript auszuführen. Manchmal jedoch haben Sie es mit einer wirklich einfachen Aufgabe zu tun oder aber mit einer einmaligen (oder zumindest sehr selten anfallenden) Aufgabe. Für Probleme dieser Art wäre es reine Zeitverschwendung, extra den Editor aufzurufen, nur um das eigentliche Skript zu schreiben. Abhilfe schaffen in diesen Fällen die einzeiligen Skripts von Perl, sogenannte Einzeiler.
Einzeiler sind Perl-Skripts, die Sie direkt an der Perl-Befehlszeile eingeben. Sie werden nirgends gespeichert. Haben Sie einen Fehler gemacht, müssen Sie sie neu eingeben.
Um einen Einzeiler in Perl zu erstellen, verwenden Sie die Option -e
gefolgt von dem
Skript in Anführungszeichen:
% perl -e 'print "Dies ist ein Einzeiler\n";'
Dies ist ein Einzeiler
%
Unter Windows müssen Sie das ganze Skript in doppelte Anführungszeichen setzen und die doppelten Anführungszeichen im Skript selbst mit einem Backslash kennzeichnen:
C:\> perl -e "print \"Dies ist ein Einzeiler unter Windows\n\";"
Arbeiten Sie mit MacPerl, so haben Sie keine Befehlszeile. Doch keine Panik! Es gibt
im Skriptmenü einen passenden Menübefehl, der die Befehlszeile simuliert und in den
Sie Ihren Perl-Einzeiler eingeben können. Aber auch hier müssen Sie das Wort perl
,
die Option -e
und das Skript in Anführungszeichen eingeben.
Wenn Ihr Skript mehrere Anweisungen enthält, so setzen Sie sie einfach alle in eine
Zeile (in den meisten Unix-Shells können Sie einen Befehl auf mehrere Zeilen
verteilen, indem Sie ein Backslash (\
) an das Ende der Zeile setzen). Zur Erinnerung:
Perl stört sich nicht an Zwischenraumzeichen (Whitespaces). Deshalb könnten Sie
theoretisch einen unglaublich komplexen Einzeiler erzeugen, und Perl hätte trotzdem
keine Probleme mit dessen Ausführung (vielleicht haben Sie auch schon den
altbekannten Spruch vieler Perl-Programmierer gehört: »Ich erledige das alles in einer
Zeile!« - was natürlich möglich ist, da man in Perl alles in einer Zeile machen kann,
fragt sich nur, wie lang die Zeile dann wird).
Sehen Sie im folgenden einige Beispiele für einzeilige Perl-Skripts.
So drehen Sie alle Zeilen in einer Datei um:
% perl -e 'print reverse <>;' dateiname.txt
So geben Sie alle Zeilen einer Datei mit Zeilennummern aus:
% perl -e '$i=1;while(<>){print "$i: $_";$i++}' dateiname.txt
So entfernen Sie alle führenden Whitespace-Zeichen aus allen Zeilen einer Datei:
% perl -e 'while(<>){s/^\s+//g;print;}' dateiname.txt
So geben Sie eine Datei in Großbuchstaben aus:
% perl -e 'while(<>){print uc $_;}' dateiname.txt
Da Skripts dieser Art häufig while
-Schleifen mit <>
und einer Form von print
verwenden, gibt es in Perl dafür eine Kurzform. Die Option -p
erlaubt Ihnen, den
while(<>)
-Teil wegzulassen und $_
dennoch Zeile für Zeile auszugeben. Demzufolge
könnte man das Beispiel zur Konvertierung in Großbuchstaben auch folgendermaßen
schreiben (ob das wirklich besser ist, müssen Sie selbst entscheiden):
% perl -p -e '$_ = uc $_;' test.txt
Diese Zeile entspricht dem folgenden Code:
while (<>) {
$_ = uc $_;
print;
}
Sie können die beiden Befehlszeilenoptionen auch zusammenfassen, müssen aber die
p
-Option vor die e
-Option stellen:
% perl -pe '$_ = uc $_;' test.txt
-p
ist nicht die einzige Perl-Option, die Ihnen in Ihren Einzeilern Tipparbeit abnehmen soll. Die Option-n
entspricht in etwa der Option-p
, erzeugt aber keinenwhile(<>)
-Schleife). Die Option-l
in Kombination mit-p
oder-n
trägt automatisch dafür Sorge, dass das Neue-Zeile-Zeichen am Ende jeder Zeile erst entfernt und dann beim Ausgeben wieder eingefügt wird. (Oder um genau zu sein,-l
setzt den Wert der Variablen$\
, dem Trennsymbol für die Ausgabedatensätze, auf$/
, dem Trennsymbol für die Eingabedatensätze - in der Regel das Neue-Zeile-Zeichen). Alternativ können Sie-l
einen oktalen Wert als zusätzliches Argument mitgeben, der das Zeichen repräsentiert, das Sie als Trennsymbol für die Ausgabedatensätze verwenden wollen.
Einzeiler können extrem leistungsfähig sein, wenn sie zusammen mit der Option -i
verwendet werden. Angenommen Sie haben einen Roman geschrieben und auf
mehrere Dateien verteilt, die alle auf die Extension .txt
enden. Jetzt wollen Sie alle
Vorkommen des Namens »Stefan« durch den Namen »Fred« ersetzen. Das einzeilige
Perl-Skript, das dies leistet, alle Originaldateien ändert und von jeder Datei eine
Sicherungsdatei anlegt, sieht wie folgt aus:
% perl -p -i.bak -e 's/Stefan/Fred/g' *.txt
Die Option -i
schreibt direkt in Ihre Originaldateien, so dass die neuen Versionen die
gleichen Dateinamen tragen wie die Originaldateien. Die alten Versionen dieser
Dateien (in denen Ihr Held noch Stefan hieß) werden in Dateien mit der Extension
.txt.bak
gespeichert. Auf diese Weise haben Sie immer noch die Möglichkeit, auf die
alten Dateien zuzugreifen, für den Fall, dass Sie vielleicht nicht Stefan, sondern Albert
in Fred umbenennen möchten. Seien Sie vorsichtig mit diesem Perl-Befehl - testen
Sie ihn zuerst einmal an einer einzigen Datei, ohne Änderungen vorzunehmen. So
können Sie sicherstellen, dass Ihr Einzeiler auch korrekt funktioniert. Sonst kann es
Ihnen passieren, dass Sie am Ende eine ganze Reihe von .bak
-Dateien restaurieren
müssen.
Eines der größeren Themen, auf das ich in diesem Buch nicht näher eingegangen bin, betrifft die Verwendung von Perl für die objektorientierte Programmierung, kurz OOP (wäre der Titel dieses Buches Perl in 25 1/2, hätten wir es vielleicht geschafft). Glücklicherweise fällt die Einarbeitung in die objektorientierte Programmierung unter Perl nicht allzu schwer, da Perl bekannte Elemente wie Pakete, Subroutinen und Referenzen verwendet, um eine objektorientierte Programmierumgebung zu schaffen. Auf diese Weise können Sie, wenn Sie sich schon etwas mit OOP auskennen, direkt - unter Beachtung bestimmter Regeln - mit der Programmierung beginnen. Wer in der objektorientierten Programmierung noch unerfahren ist, muss sich zuerst etwas Hintergrundwissen aneignen. Irgendwelche neuen größeren Perl-Features brauchen Sie nicht zu lernen, um Ihre Kenntnisse in objektorientierter Programmierung direkt umzusetzen.
Wenn Sie mit objektorientierter Programmierung noch nicht vertraut und daran interessiert sind, objektorientiert zu programmieren, sollte Ihr erster Schritt darin bestehen, dass Sie sich die Grundkonzepte anschauen. Objektorientierte Programmierung bedeutet einfach, dass Sie das gleiche Programmierproblem aus einem anderen Blickwinkel betrachten. Alles, was Sie bisher in diesem Buch über Syntax und guten Programmierstil gelernt haben, behält seine Gültigkeit. Der Unterschied liegt darin, wie Ihr ganzes Skript organisiert ist und wie es sich verhält.
Der Grundgedanke, der der objektorientierten Programmierung zugrunde liegt, ist, dass Ihr Skript keine Sammlung von nacheinander ausgeführten Anweisungen und Subroutinen ist, sondern eine Sammlung von Objekten, die in einer vordefinierten Art und Weise miteinander interagieren. Jedes Objekt hat eine definierte Erscheinung oder Status (Variablen) und einen definierten Satz an Verhaltensweisen (Subroutinen, in OOP auch Methoden genannt). Objekte erhalten diese Verhaltens- und Statusschablonen von einer Klassendefinition. Diese Klassendefinition wiederum erbt (verwendet) oftmals die Merkmale von einer oder mehreren anderen Klassen. Wenn Sie ein objektorientiertes Skript erstellen, erzeugen Sie eine oder mehrere eigene Klassen, die Klassen und Objekte von anderen Quellen (in der Regel Module) importieren und verwenden. Wenn Ihr Perl-Skript ausgeführt wird, werden aus den verschiedenen Klassen Laufzeitobjekte erstellt, die untereinander ihre Variablen ändern und ihre jeweiligen Subroutinen aufrufen, um am Ende eine Art von Ergebnis zu liefern.
Hat Sie der obige Absatz zu Tode erschreckt, dann geraten Sie bitte nicht in Panik. In Perl können Sie sich langsam mit OOP anfreunden und bereits die ersten OOP- Konzepte nutzen, ohne gleich alle Konzepte und Techniken kennen zu müssen. Und außerdem gibt es im Netz eine Fülle von OOP-Tutorials, die Ihnen helfen, die Theorie und die verschiedenen Konzepte der objektorientierten Programmierung zu verstehen. Die folgenden Vorschläge sind ganz gute Ausgangspunkte:
http://www.progsoc.uts.edu.au/~geldridg/cpp/
finden Sie eine Reihe
von Links zu verschiedenen Stellen mit OOP-bezogenen Informationen - nicht
unbedingt Perl-spezifisch, aber mit einigen einführenden Tutorials.
www.typerl.com
). OOP-Konzepte
lassen sich in der Regel von einer Sprache auf eine andere übertragen.
Sollten Sie immer noch verzagt sein, ist auch das noch kein Grund, in Panik zu verfallen. Zwar wird OOP von vielen als der Trend der Zukunft betrachtet, doch wenn Sie zufrieden damit sind, mit dem guten alten Perl weiterzuarbeiten, und niemand von Ihnen erwartet, sich in OOP einzuarbeiten, spricht nichts dagegen, sich an das Altbewährte zu halten. Denn schließlich führen viele Wege nach Rom.
Sie wissen also bereits, was ein Objekt ist und wie es sich zu einer Klasse verhält. Und Sie kennen die Begriffe Instanzvariable, Methode, Vererbung, Konstruktor, Destruktor und Kapselung. Dann lassen Sie uns diese Terminologie auf Perl übertragen.
In Perl ist eine Klasse ein Paket, und der Namensbereich, der vom Paket definiert wird, definiert die Kapselung und den Gültigkeitsbereich für diese Klasse. Variablen, die in diesem Paket definiert werden, sind Klassenvariablen (statische Variablen). Instanzvariablen werden normalerweise dadurch erzeugt, dass man eine Referenz auf einen Hash erzeugt und als Schlüssel den Namen der Instanzvariablen verwendet. Klassen- und Instanzmethoden werden beide als Subroutinen definiert. Der einzige Unterschied zwischen einer Methode und einer regulären Subroutine ist der, dass eine Methode als erstes Argument einen Klassennamen (für Klassenmethoden) oder eine Objektreferenz (für Instanzmethoden) erwartet.
Eine Objektreferenz? Gut aufgepaßt. Das ist das einzig Neue, das Sie, soweit es Perl
betrifft, lernen müssen, um in Perl objektorientiert programmieren zu können. In Perl
ist ein Objekt eine Referenz auf eine Datenstruktur (in der Regel ein anonymer leerer
Hash), die mit einer speziellen Markierung versehen wurde, so dass sie sich wie ein
Objekt verhält und weiß, zu welcher Klasse sie gehört. Um etwas als ein Objekt zu
markieren, verwenden Sie die vordefinierte bless
-Funktion. Diese Funktion liefert
eine Referenz auf ein Objekt zurück, die Sie dann wiederum, wie jede andere Referenz
auch, einer Skalarvariablen zuweisen können.
Normalerweise verwenden Sie bless
in dem Konstruktor Ihrer Klasse. Der
Konstruktor ist eine ganz normale Subroutine, die per Konvention new
genannt wird.
Die bless
-Funktion übernimmt zwei Argumente: das, wofür Sie eine Objektreferenz
erstellen wollen, und den Namen einer Klasse. Eine einfache Klassendefinition könnte
damit wie folgt aussehen:
package MeineKlasse;
sub new {
my $klassenname = shift;
my $selbst = {};
return bless $selbst, $klassenname;
}
In diesem Beispiel wird davon ausgegangen, dass die Klassenmethode new
mit einem
Argument aufgerufen wird: einem Klassennamen. In new
selbst erzeugen wir einen
leeren, anonymen Hash, markieren ihn mittels bless
mit dem aktuellen
Klassennamen und liefern eine Referenz auf den Hash zurück. Beachten Sie, dass new
eine Klassenmethode ist und dass Klassenmethoden immer als erstes Argument den
Namen der Klasse erhalten.
Sie können
bless
auch mit nur einem Argument verwenden (dem Element, das mitbless
markiert werden soll), und Perl wird den Namen der aktuellen Klasse automatisch als zweites Argument verwenden. Aufgrund der Art und Weise wie Perl jedoch mit vererbten Methoden umgeht, kann die Verwendung von nur einem Argument zu falschen Ergebnissen führen, wenn eine andere Klasse Ihren Konstruktor erbt. Allgemein möchte ich Ihnen nahelegen, sich daran zu gewöhnen,bless
mit zwei Argumenten zu verwenden, und den Klassennamen der Argumentliste der Methode zu entnehmen.
Um ein Objekt zu erzeugen und zu verwenden (aus dieser Klasse oder aus irgendeiner
anderen Klasse), rufen Sie die Methode new
zusammen mit einem Paket- (Klassen-)
namen auf. Sie können dies in der gleichen Datei erledigen, in der auch Ihre
Klassendefinition steht, solange Sie vorher in package main
wechseln:
package main;
$obj = new MeineKlasse;
Die Skalarvariable $obj
enthält dann eine Referenz auf ein Objekt, das durch die
Klasse MeineKlasse
definiert ist. Alternativ können Sie auch die Pfeilsyntax (mit ->
)
verwenden, um den new
-Konstruktor aufzurufen:
$obj = MeineKlasse->new();
Beide Möglichkeiten, new
aufzurufen, führen zum gleichen Ergebnis. Wenn Ihr new
-
Konstruktor jedoch neben dem Klassennamen noch weitere Argumente benötigt, ist
es oft leichter, das letztere Format anzuwenden:
$obj = MeineKlasse->new(12, 240, 15);
Um die Methoden aufzurufen, die in Ihrem neuen Objekt definiert sind, müssen Sie die Objektreferenz dereferenzieren. Dafür eignet sich die ->-Syntax besonders gut:
$obj->eineSubroutine('foo','bar');
Alternativ gibt es für Methoden eine Syntax, die stärker an die normale Funktionsaufruf-Syntax angelehnt ist. Dabei muss das erste Argument zu der Methode der Klassenname oder eine Objektreferenz sein:
eineSubroutine $obj, 'foo', 'bar';
Da das erste Argument hier eine Objektreferenz ist, wird Perl die Referenz für Sie dereferenzieren und die richtige Methode aufrufen.
Sie können eine Methode auch wie eine Funktion in einem Paket aufrufen
((Myclass::eineSubroutine(...)
). Diese Vorgehensweise empfiehlt sich aber nur,
wenn Sie genau wissen, was Sie machen. Damit untergraben Sie nämlich die OOP-
Eigenschaften der Klasse und verlieren die Fähigkeit, an eine Methodendefinition zu
gelangen, die Ihnen über Vererbung zur Verfügung steht. Im nächsten Abschnitt
»Instanzvariablen« erzähle ich Ihnen noch mehr zum Definieren und Aufrufen von
Referenzen.
Wenn Sie wie oben beschrieben Objekte erzeugen, verwenden Sie einen anonymen
Hash als das, was Sie mit bless
als Objekt markieren. Warum gerade einen Hash?
Weil ein Hash zum Speichern und Zugreifen auf Instanzvariablen genutzt werden kann
und Sie jedesmal eine neue Version dieser Variablen erhalten. Auf diese Weise
werden alle internen Objektstatusinformationen in Perl-Objekten gespeichert.
In manchen OOP-Sprachen wird zwischen Instanzvariablen und Klassenvariablen unterschieden (letztere werden manchmal auch als statische Daten bezeichnet). Perl kennt an sich keine Klassenvariablen. Sie können zwar jederzeit globale Paketvariablen erstellen, die die Funktion von Klassenvariablen haben, und auf diese dann über die normale Paketsyntax
($MeineKlasse::meineKlassenVar
) zugreifen, allerdings werden diese Variablen nicht vererbt und können von jedem Benutzer Ihrer Klasse beliebig geändert werden. Versuchen Sie, die Verwendung von Klassenvariablen zu umgehen und statt dessen Instanzvariablen zu verwenden.
Im allgemeinen werden die Instanzvariablen einer Klasse in dem Konstruktor der
Klasse definiert und initialisiert. Häufig werden Sie dabei Argumente an new
übergeben, die die Anfangswerte dieser Klasse bilden sollen:
#!/usr/bin/perl -w
package Rectangle;
sub new {
my ($classname, $w, $h) = @_;
my $self = {};
$self->{Width} = $w;
$self->{Height} = $h;
return bless $self, $classname
}
sub area {
my $self = shift;
return $self->{Width} * $self->{Height};
}
package main;
$sq = new Rectangle (12, 20);
print "Fläche: ", $sq->area(), "\n";
In diesem Beispiel haben wir einen Klassenkonstruktor verwendet, der zwei
zusätzliche Argumente übernimmt - eine Breiten- und eine Höhenangabe. Auf der
Grundlage dieser Argumente erzeugt der Konstruktor ein Rectangle
-Objekt
(Rechteck) und speichert die Werte in dem Hash des Objekts unter den Schlüsseln
Width
und Height
. Des weiteren haben wir eine Methode namens area
erzeugt, die
die aktuellen Werte dieser Instanvariablen multipliziert und das Ergebnis zurückliefert.
Im allgemeinen sieht die objektorientierte Programmierung mit Instanzvariablen in Perl so aus, dass Sie zum Schreiben und Lesen dieser Variablen Methoden definieren und verwenden, anstatt die Werte der Variablen durch direkte Zuweisung zu ändern. Dies ist insbesondere bei der Vererbung von Vorteil und sorgt dafür, dass Ihre Klasse oder Ihr Objekt eine »reinere« objektorientierte Schnittstelle erhält. Sie können aber auch mit der normalen Dereferenzierungssyntax auf die Instanzvariablen zugreifen:
# kein objektorientierter Variablenzugriff
print "Width: $sq->{Width}\n";
print "Height: $sq->{Height}\n";
Wie jede ordentliche objektorientierte Programmiersprache erlaubt auch Perl die Vererbung von Klassen, die es Klassen erlaubt, die Definitionen anderer Klassen zu verwenden und zu erweitern. Wenn die Klasse B das Verhalten von Klasse A erbt, wird Klasse A als Basis- oder Superklasse und Klasse B als abgeleitete oder Subklasse bezeichnet.
Um anzuzeigen, dass eine Klasse von einer anderen Klasse erbt, verwenden Sie das
spezielle Array @ISA
. Das Array @ISA
legt fest, in welchen Klassen nach
Methodendefinitionen gesucht wird, wenn die Definition einer aufgerufenen Methode
nicht in der aktuellen Klasse existiert. Wenn Sie zum Beispiel eine Superklasse Katzen
hätten, würde die Subklasse Tiger
wie folgt aussehen:
package Tiger;
@ISA = qw( Katzen );
...
Wenn eine Klasse nur von einer Superklasse erbt, ist der Aufruf von qw
nicht
unbedingt erforderlich, erleichtert aber das Hinzufügen weiterer Superklassen, falls
man sich später für eine Mehrfachvererbung entscheidet:
package Hauskatze;
@ISA = qw( Katze Haustier );
...
Wenn für eine Methode, die über ein bestimmtes Objekt aufgerufen wird, in der
aktuellen Klassendefinition keine Definition gefunden wird, geht Perl das @ISA
-Array
durch und sucht in jeder der aufgelisteten Superklassen nach der betreffenden
Methodendefinition. Gibt es zu einer Superklasse wieder weitere Superklassen werden
diese ebenfalls durchsucht, bevor die nächste Superklasse im @ISA
-Array an die Reihe
kommt. Nehmen wir an, die Methode fressen
wird für ein Objekt der Klasse
Hauskatze
aufgerufen. Zuerst wird in Hauskatze
selbst nach einer Definition gesucht,
dann in Katze
und dann in allen Superklassen von Katze
(falls vorhanden) und in
deren Superklassen, bevor die Suche nach der Definition in Haustier
fortgeführt wird.
Die Definition, die zuerst gefunden wird, wird auch verwendet.
Perl vererbt nur Methoden. Um Instanzvariablen zu »vererben«, können Sie geerbte Konstruktormethoden verwenden, um einen einzigen Hash von Instanzvariablen einzurichten, der die Instanzvariablen sämtlicher Superklassen aufnimmt - plus denen, die für die aktuelle Klasse definiert wurden. (Ein Beispiel hierfür finden Sie in der Manpage perlobj.)
Das Definieren von Methoden kann in drei allgemeine Kategorien unterteilt werden:
Methoden, die von der Vererbung keinen Gebrauch machen, werden als gewöhnliche Subroutinen in der Klassen-(Paket-)Definition aufgesetzt. Die einzige Besonderheit ist das erste Argument zu dieser Subroutine, das festlegt, ob die Methode eine Klassen- oder eine Instanzmethode ist.
Im Falle von Instanzmethoden ist das erste Argument eine Objektreferenz.
Normalerweise wird bei Methoden dieser Art zuerst einmal die Referenz aus der
Argumentliste extrahiert und in einer Skalarvariablen gespeichert ($self
ist ein sehr
geläufiger Variablenname, er kann aber auch beliebig anders lauten):
sub meineMethode {
my $self = shift;
...
}
Bei Klassenmethoden ist das erste Argument einfach der Name der Klasse - nichts Besonderes, nur ein String. Auch hier werden Sie für gewöhnlich das Argument extrahieren und es in einer Skalarvariablen speichern.
Wie sieht es jetzt aber mit Methoden aus, die je nach Argument entweder eine
Klassen- oder eine Instanzmethode sein können. Für solche Methoden brauchen Sie
einen Weg, wie Sie im Rumpf der Methode feststellen können, ob es sich bei dem
ersten Argument um ein Objekt oder eine Klasse handelt. Sehr hilfreich ist in diesem
Zusammenhang die Funktion ref
:
sub klasseOderInstanz {
my $arg = shift;
if (ref($arg)) {
print "Argument ist ein Objekt\n";
} else {
print "Argument ist ein Klassenname\n";
}
}
Beachten Sie, dass die ref
-Funktion, wenn sie mit einer Objektreferenz als Argument
aufgerufen wird, den Namen der Klasse zurückliefert, von der das Objekt eine Instanz
darstellt.
Wenn Sie eine Methode aufrufen, die in der aktuellen Klasse definiert ist, wird diese Methode ausgeführt - auch wenn es weiter oben in der Vererbungskette eine gleichnamige Methode gibt. Dies ist der Weg, wie Sie Methoden definieren, die bestehende Methoden überschreiben - einfach definieren und fertig.
Wenn Sie das Verhalten einer Methode einer übergeordneten Klasse ergänzen wollen,
anstatt es komplett zu überschreiben, verwenden Sie das Paket SUPER
, das Perl
anweist, in den in @ISA
aufgeführten Klassen nach einer Methodendefinition zu
suchen:
sub berechnen {
my $self = shift;
my $sum = $self->SUPER::berechnen(); # zuerst die Superklassen
foreach (@_) {
$sum += $_;
}
return $sum;
}
SUPER
wird häufig in geerbten Konstruktoren (new
-Methoden) verwendet. MitSUPER
können Sie einen Konstruktor erzeugen, der die Vererbungskette hinaufläuft, um sicherzustellen, dass das aktuelle Objekt über alle Instanzvariablen und Initialisierungen verfügt, die es benötigt.
Ich habe Ihnen bereits gezeigt, wie Sie Konstruktormethoden mit bless
erzeugen. Sie
können aber auch Destruktormethoden erzeugen, die ausgeführt werden, wenn alle
Referenzen auf das Objekt gelöscht sind und das Objekt nur noch darauf wartet, von
der Speicherbereinigung entfernt zu werden. Sie erzeugen eine Destruktormethode,
indem Sie eine Subroutine namens DESTROY
in Ihrer Klasse definieren:
sub DESTROY {
print "Objekt löschen\n";
...
}
In Verbindung mit den Methodenaufrufen gibt es in Perl eine nette Besonderheit, die
ich Ihnen nicht vorenthalten möchte: die sogenannten selbstladenden Methoden.
Selbstladende Methoden stellen eine Art letzte Zuflucht dar, wenn Sie für ein Objekt
eine Methode aufrufen, für die Perl keine passende Definition finden kann. In diesem
Fall versucht Perl, eine Methode namens AUTOLOAD
aufzurufen. Die Paketvariable
$AUTOLOAD
enthält den Namen der Methode, die aufgerufen wurde (einschließlich des
ursprünglichen Klassennamens, für den sie aufgerufen wurde). Sie können diese
Informationen dann nutzen, um festzulegen, wie ansonsten unbekannte
Methodenaufrufe verarbeitet werden sollen. Die Manpage perlobj enthält ein
hervorragendes Beispiel dafür, wie man mit Hilfe einer selbstladenden Methode
Zugriffsmethoden für Instanzvariablen simulieren kann, ohne dass man tatsächlich für
jede Variable eine eigene Methode definieren müßte. Im folgenden finden Sie ein
einfaches Beispiel für eine selbstladende Methode, die diese Art von Verhalten zeigt:
package Hauskatze;
@ISA = qw( Katze, Haustier );
sub new {
my $classname = shift;
return bless {}, $classname;
}
sub AUTOLOAD {
my ($self,$arg) = @_;
my $name = $AUTOLOAD;
my $iv =~ s/.*://; # Paket-Teil aus Namen entfernen
if ($arg) { # Wert setzen
$self->{$iv} = $arg;
return $arg;
} else { # kein Argument, Rückgabewert zurückliefern
return $self->{$iv};
}
}
package main;
my $cat = new Hauskatze;
$cat->color("Grau");
print "Meine Katze ist $cat->color()\n";
In diesem Beispiel hat die Klasse Hauskatze
keine Methode namens color
(und wir
gehen davon aus, dass die übergeordneten Klassen ebenfalls keine Methode dieses
Namens haben). Wenn die Methode color
aufgerufen wird, ruft Perl daher AUTOLOAD
auf. In der Definition von AUTOLOAD
erhalten wir den Namen der aufgerufenen
Methode über die Variable $AUTOLOAD
, entfernen den Paketnamen zu Beginn und
verwenden den übriggebliebenen Methodennamen dann als Namen der
Instanzvariablen. Wurde die Methode mit einem Argument aufgerufen, weisen wir
diesen der Instanzvariablen zu. Andernfalls geben wir einfach den aktuellen Wert aus
(es obliegt dem Aufrufer, undefinierte Instanzvariablen zu handhaben). Sie können
diese AUTOLOAD
-Methode genau so einfach auch für alle anderen Instanzvariablen
verwenden - name
, alter
, temperament
, lieblingsessen
und so weiter.
Technisch gesehen, stellen
AUTOLOAD
-Methoden nicht unbedingt die letzte Zuflucht dar. Zusätzlich zuAUTOLOAD
gibt es noch die KlasseUNIVERSAL
.UNIVERSAL
ist eine Art globale Superklasse. In ihr können Sie Ihre Zufluchtsmethoden definieren.
In Perl ist OOP kein Dogma, sondern eine optionale Möglichkeit. Sie können OOP nur sporadisch einsetzen oder die Sache gründlich angehen und OOP konsequent überall verwenden. Das hängt ganz davon ab, was am leichtesten ist und wie fanatisch Sie den Grundprinzipien der objektorientierten Programmierung anhängen.
In vielen Fällen nutzt man die Vorzüge der objektorientierten Programmierung am
einfachsten dadurch, dass man die verschiedenen objektorientierten CPAN-Module in
die eigenen Skripts einbindet - ohne dass man dazu notwendigerweise die eigenen
Skripts als einen Satz von Objekten strukturieren müßte. Erinnern wir uns noch
einmal an die CGI-Skripts und das Modul CGI.pm
von Tag 16, »Perl für CGI-Skripts«.
Dieses Modul ist so geschrieben, dass seine Subroutinen sowohl als einfache
Subroutinen als auch als objektorientierte Methoden verwendet werden können.
Betrachten wir eine der Übungen, die wir am Ende der Lektion gemacht haben -
Übung 1, ein CGI-Skript, das nur die ihm übergebenen Schlüssel und Werte ausgibt -
und setzen wir das CGI-Modul diesmal objektorientiert ein.
Das Originalskript sehen Sie noch einmal in Listing 20.1
1: #!/usr/bin/perl -w
2: use strict;
3: use CGI qw(:standard);
4:
5: my @keys = param();
6:
7: print header;
8: print start_html('Hallo!');
9: print "<H1>Schlüssel/Wert-Paare</H1>\n";
10: print "<UL>\n";
11:
12: foreach my $name (@keys) {
13: print "<LI>$name = ", param($name), "\n";
14: }
15: print "</UL>\n";
16:
17: print end_html;
Wir verwenden in diesem Skript vier Subroutinen aus dem CGI-Moduls: param
(Zeilen
5 und 13), die uns die gesamte Liste der verfügbaren Schlüssel und deren Werte
liefert, header
(Zeile7), um einen CGI-Header auszugeben, start_html
(Zeile 8), um
den oberen Teil einer HTML-Datei auszugeben, und end_html
(Zeile 17), um den
unteren Teil einer HTML-Datei auszugeben. Im obigen Beispiel haben wir diese
Subroutinen als reguläre Subroutinen verwendet.
Das CGI-Modul kann aber auch als eine objektorientierte Klasse verwendet werden. Erzeugen Sie eine Instanz dieser Klasse, und Sie können die Subroutinen verwenden, als ob es sich dabei um Methoden handeln würde (was sie ja auch eigentlich sind). Alles was hierzu nötig ist, ist eine zusätzliche Codezeile und eine etwas abgeänderte Syntax für die Subroutinen (siehe Listing 20.2).
Listing 20.2: Die objektorientierte Version von paare1.pl
1: #!/usr/bin/perl -w
2: use strict;
3: use CGI qw(:standard);
4:
5: my $obj = CGI->new();
6: my @keys = $obj->param();
7:
8: print $obj->header();
9: print $obj->start_html('Hallo!');
10: print "<H1>Schlüssel/Wert-Paare</H1>\n";
11: print "<UL>\n";
12:
13: foreach my $name (@keys) {
14: print "<LI>$name = ", $obj->param($name), "\n";
15: }
16: print "</UL>\n";
17:
18: print $obj->end_html();
Sehen Sie die Unterschiede? Eigentlich sind es nur zwei:
$obj
. Entsprechend den Perl-Konventionen heißt der
Objektkonstruktor für die CGI-Klasse new
.
param
, start_html
, header
und end_html
- werden als
Objektmethoden mittels der Dereferenzierungssyntax (das Objekt, ->
und der
Name der Methode) aufgerufen.
Und das Endergebnis? Es gibt keinen Unterschied zu der Nicht-OOP-Version. Das CGI-Modul ist so geschrieben, dass es gleichermaßen gut als normale Sammlung von Subroutinen oder als objektorientierte Klasse verwendet werden kann.
Beachten Sie, dass es sich bei diesem Beispiel nicht um ein »reines« OOP-Programm handelt. Wir haben hier keine eigenen Klassen erzeugt. Ein »wahres« OOP-Skript würde den Großteil des Codes in einer eigenen Klasse unterbringen und dort das CGI- Modul nutzen. Im Hauptteil würde kaum mehr als die Instantiierung der Klasse und die Aufrufe von ein oder zwei Methoden stehen, um das Skript in Gang zu setzen. Das ist das Gute an OOP in Perl. Sie müssen nur so viel objektorientierte Programmierung einsetzen wie nötig. Im Gegensatz zu anderen strengeren OOP-Sprachen, müssen Sie Code, der für OOP ungeeignet erscheint, nicht unbedingt in Objekte pressen.
In Anbetracht der Tatsache, dass Perl ein Akronym für Practical Extraction and Report Language (Praktische Extraktions- und Reportsprache) ist, mag es Sie überraschen, dass bisher in diesem Buch zwar viel über das Extrahieren geschrieben wurde, aber kaum etwas über das Protokollieren. Für letzteres gibt es die Formate: zur Ausgabe von formatierten textbasierten Protokollen über Informationen, die Sie vorher gelesen, verarbeitet oder anderweitig malträtiert haben.
Warum wird dieses Thema erst jetzt gegen Ende des Buchs angesprochen? Ein großer
Teil der Ausgabe von Perl-Skripts erfolgt heutzutage - als Ergebnis von CGI-Skripts -
im HTML-Format und nicht mehr im Nur-Text-Format. Wenn Sie also davon
ausgehen, dass Sie Perl hauptsächlich für CGI einsetzen werden, ist HTML für die
Ausgabe besser geeignet als reiner Text. Wenn Sie aber vornehmlich mit einfacher
Textausgabe arbeiten, sollten Sie sich unbedingt mit den Formaten befassen, vor
allem auch unter dem Aspekt, dass print
-Anweisungen ziemlich umständlich sind, um
eine ordentliche und übersichtliche Präsentation Ihrer Ausgabe sicherzustellen.
Die Idee hinter den Formaten ist die, dass Sie mit Hilfe der format
-Funktion eine
spezielle Schablone (Template) deklarieren, die festlegt, wie Ihre Ausgabe auszusehen
hat, und dann mit der write
-Funktion und einem Datei-Handle diese Schablone auf
die Daten anwenden. Als Ergebnis werden die Platzhalter in der Schablone durch
einen Satz von Werten aus der gegebenen Datenmenge ersetzt. Die Schablone legt
die Position einer jeden Datenspalte sowie ihre Breite und Ausrichtung fest. Zusätzlich
steht Ihnen eine Reihe von speziellen Perl-Variablen für die Größe einer Seite (in
Zeilen), den Header (Kopfbereich), der oben auf jeder Seite erscheinen soll, und die
aktuelle Seitenzahl zur Verfügung. Insgesamt können Sie so für jede beliebige Art von
Daten Protokolle mit Ganzseiten-Textformatierung erzeugen.
Schablonen werden mit Hilfe der Funktion format
deklariert. Schablonennamen
verhalten sich wie Subroutinen- oder andere Variablennamen, sie unterliegen den
gleichen Regeln zur Namensgebung und geraten nicht mit den Namen anderen Arten
von Variablen in Namenskonflikt. Eine format
-Deklaration enthält einen Namen, eine
Reihe von Bildzeilen, die festlegen, wie das Format aussehen soll, und einen Satz an
Variablen, die die Daten festlegen, die in die Schablone passen sollen. Das Format
endet mit einem einzelnen Punkt in einer eigenen Zeile. Im folgenden sehen Sie ein
Beispiel für ein einfaches Format, das eine Reihe von Firmen mit Börsenticker-
Symbolen, Höchstpreisen, Niedrigstpreisen und Abschlußpreisen ausgibt:
format STDOUT =
@<<<<<<<<<<<<<<<<<<@||||@|||||@|||||@|||||
$name, $sym,$high,$low, $current
.
Bildzeilen enthalten Symbole für einfache, einzeilige Spalten (@
) oder einfache, gefüllte
Textspalten (^
). Jede Zeile kann auf vielfältige Weise mit verschiedenen Symbolen (<
,
|
, >
, #
) ausgerichtet werden (links, zentriert, rechts, numerisch). Die Variablen geben
an, welche Daten an den einzelnen Positionen im Format stehen sollen, wenn die
Zeile ausgegeben wird. Wenn Sie use strict
verwenden, müssen Sie diese Variablen
vorher mit my
deklarieren, bevor Sie sie in dem Format verwenden können.
Um die formatierten Daten an ein Datei-Handle auszugeben, verwenden Sie die
write
-Funktion:
write STDOUT;
Beachten Sie, dass der Name des Formats mit dem Namen des Datei-Handles, an das
die Ausgabe erfolgt, übereinstimmen muss (obwohl Sie dies mit dem Modul
FileHandle
ändern können). In unserem Fall habe ich das Standard-Datei-Handle
STDOUT
verwendet.
Betrachten wir noch ein Beispiel. Unsere Daten sind eine einfache Aufgabenliste,
wobei der Datensatz aus den folgenden Feldern besteht: Zeitpunkt der Fertigstellung,
Priorität der Aufgabe (1 bis 5), ob erledigt oder nicht (0
oder 1
) und einer
Textbeschreibung der Aufgabe (ein String von ungefähr 40 Zeichen oder weniger).
Diese Daten sind in einer Datei gespeichert und werden in ein Array von Hashes
(@data
) eingelesen (siehe gestrige Lektion). Ihr Skript soll unter anderem dazu in der
Lage sein, die Aufgabenliste nach Prioritäten sortiert in einem ansprechenden Format
auszugeben. Eine entsprechende Ausgabe könnte zum Beispiel wie folgt aussehen:
Fertig? Fälligkeit Priorität Beschreibung
------------------------------------------------------------
Nein 23.10.1998 1 Kapitel 21 beenden
Nein 31.10.1998 1 Kapitel 20 beenden, überarbeiten
Nein 05.01.1999 2 Treffen mit Fred zum Essen
Ja 05.12.1998 3 Punkt 3
Nein 10.01.1999 5 Pyramide bauen
Um diese Daten ohne Formate auszugeben, würden Sie eine foreach
-Schleife
aufsetzen, die jeden Datensatz durchläuft, daraus eine Zeile aufbaut und diese dann an
den Datei-Handle ausgibt. Da Sie keine Formate verwenden, müssen Sie selbst die
Abstände zwischen den Daten kontrollieren, um sicherzustellen, dass die Daten
korrekt ausgerichtet werden. Mit Formaten ist die ordentliche Ausrichtung der Daten
wesentlich einfacher.
Um die Daten zu formatieren und auszugeben, überlegen wir zuerst, wie die Ausgabe
mit der format
-Deklaration aussehen soll. Genau genommen verwenden wir zwei
format
-Deklarationen: eine einfache Nur-Text-Deklaration für den Header und eine
für die Datenzeilen. Außerdem deklarieren wir schon einmal unsere Formatvariablen,
damit uns use
strict
keinen Ärger macht:
my ($done, $date, $prior, $desc); # Formatvariablen;
format STDOUT_TOP =
Fertig? Fälligkeit Priorität Beschreibung
------------------------------------------------------------
.
format STDOUT =
@|||| @<<<<<<<<< @| @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$done, $date, $prior, $desc
.
Die erste format
-Deklaration (für STDOUT_TOP
) ist eine besondere Art von Format, die
einen Header für die Seite definiert. Header haben per definitionem den gleichen
Namen wie das normale Format (hier STDOUT
) plus dem angehängten _TOP
. Sie
könnten diesen Test als normale print
-Anweisung ausgeben, aber formatierte Header
haben den Vorteil, dass sie bei einem mehrseitigen Ausdruck auf jeder Seite
automatisch gleich ausgegeben werden. Ich persönlich finde, dass sie das Formatieren
stark vereinfachen, deshalb nehme ich sie meistens mit auf.
Kommen wir jetzt zu dem interessanteren, dem zweiten Format, das unsere
eigentliche format
-Deklaration enthält. Hier definieren wir die Breite und Ausrichtung
all unserer Spalten: done
und prior
sind zentriert (beachten Sie das |
-Zeichen), date
und desc
sind links ausgerichtet (<
-Zeichen). Die Anzahl der Ausrichtungszeichen legt
die Anzahl der Zeichen für die Spalte fest. Weisen die Daten mehr Zeichen auf, als die
Spalte Zeichen
aufnehmen kann, werden diese abgeschnitten.
Nachdem die Formate definiert sind, besteht der zweite Schritt darin, die Daten in einer Schleife zu durchlaufen und auszugeben. Doch zuerst sortieren wir die Datensätze nach ihrer Priorität:
my @sorteddata = sort { $a->{'prior'} <=> $b->{'prior'} } @data;
Anschließend durchlaufen wir die Daten und geben sie aus:
foreach (@sorteddata) {
my %rec = %$_;
if ($rec{'fertig'}) {
$done = 'Ja';
} else {
$done = 'Nein';
}
$date = $rec{'datum'};
$prior = $rec{'prior'};
$desc = $rec{'desc'};
write STDOUT;
}
Für jeden Teil jedes Datensatzes weisen Sie den temporären Variablen aus dem
Format die auszugebenden Daten zu (die Variablen $done
, $date,
$prior
und $desc
).
Die Daten für die Variable $done
haben eigentlich die Werte 0
oder 1
. In unserem
Beispiel ersetzen wir diese Werte durch Ja
oder Nein
, um das Ergebnis anschaulicher
zu machen.
Nachdem alle Variablen gesetzt wurden, besteht der letzte Schritt aus einer write
-
Anweisung, die das entsprechende Format verwendet, um eine Zeile von Daten
auszugeben, und dann zum nächsten Datensatz in der Zeile weitergeht.
Weitere Informationen zu den Formaten finden Sie in der perlform-Manpage. Es
lohnt sich auch, einen Blick auf die formatspezifischen Perl-Variablen in der perlvar-
Manpage zu werfen, wo Format-Header, Seitenzahlen und anderes beschrieben sind.
Schließlich gibt es noch das FileHandle
-Modul, das Ihnen eine objektorientierte
Schnittstelle zu den Datei-Handles und den Formaten bietet und die Arbeit mit vielen
der in Perl definierten Elemente zur Verwaltung mehrerer Formate und Datei-Handles
erleichtert.
Netzwerke waren schon seit jeher eine Stärke von Unix, und Perl wäre schlecht beraten, wenn es nicht Zugriff auf die Netzwerk-Features von Unix bieten würde - insbesondere die TCP- und UDP-Sockets. Perl stellt eine Reihe von eigenen Funktionen für die Arbeit mit Sockets bereit (siehe Tabelle 20.1), die das gleiche Verhalten aufweisen wie ihre C-Gegenstücke. Wenn Sie in socketbasierter Programmierung bereits Erfahrung sammeln konnten, werden Ihnen diese Funktion vertraut vorkommen. Darüber hinaus können Sie das Socket-Modul nutzen, das Ihnen Zugriff auf die allgemeinen Socket-Strukturdefinitionen in C bietet.
Die Verwendung von Sockets in Perl hat jedoch auch seine Einschränkungen. Zum einen stehen Ihnen die meisten der Socket-Features von Perl nur unter Unix zur Verfügung. Unter Windows oder auf Macintosh-Rechner müssen Sie auf die entsprechenden Elemente von Win32 oder MacPerl zurückgreifen, wodurch Ihr Skript nicht mehr so portabel ist. Außerdem gilt es zu bedenken, dass die Chancen meist sehr gut stehen, dass die Aufgaben, die Sie mit Hilfe der Sockets erledigen wollen, bereits als Modul vorhanden sind - es sei denn, Sie wollen irgendein Netzwerkprotokoll implementieren, das nicht dem Standard entspricht. So lohnt es sich kaum, irgendwelche Teile für einen Webserver oder Webbrowser aufzusetzen, da es hinreichend Module gibt, die Ihnen diese Arbeit bereits abgenommen haben. Alles, was Sie tun müssen, ist, diese Module zu nutzen. Morgen werden wir uns hierzu ein Beispiel anschauen, das von den besonders nützlichen Modulen der LWP (Bibliothek für WWW-Zugriff in Perl) Gebrauch macht.
Suchen Sie im CPAN, vor allem im Abschnitt zu den Netzwerken, nach Modulen, die für einen Großteil der Netzwerkaufgaben, die Sie erledigen müssen, fertige Lösungen parat haben. Sollten Sie hier nicht fündig werden, schlagen Sie in der perlipc- Manpage nach, in der Sie weitere Informationen darüber finden, wie man Sockets verwendet (einschließlich einfacher Client- und Server-Beispiele).
In Tabelle 20.1 finden Sie die vordefinierten Funktionen für Sockets. Details zu diesen Funktionen befinden sich in der perlfunc-Manpage.
Tabelle 20.1: Socket-Funktionen
POD (ein Akronym für Plain Old Documentation, übersetzt mit »einfache, alte Dokumentation«) ist eine einfache Formatiersprache zum Erstellen von Dokumentationen zu Ihren Perl-Skripts oder -Modulen. In der Regel nehmen Sie diese Dokumentation direkt in Ihre Skriptdatei mit auf. Auf diese Art und Weise halten Sie das Skript und seine Dokumentation zusammen und müssen nicht beides getrennt warten. (Perl wird den POD-Inhalt einfach ignorieren, wenn Sie Ihre Skripts ausführen).
Um sich den POD-Inhalt Ihres Skripts (oder die POD-Dateien, die nur den POD-Inhalt
enthalten) anzuschauen, können Sie das Skript perldoc
verwenden (wird mit Perl
ausgeliefert), mit dem sie den Text der Dokumentation auf Ihrem Bildschirm anzeigen
lassen können. Sie können aber auch einen Übersetzer verwenden, der die POD-
Dateien in ein anderes Format konvertiert - zum Beispiel pod2text
für Textdateien,
pod2html
für HTML, pod2man
für nroff
-formatierte Manpages oder pod2latex
für
LaTeX-Formatierung. Bisher werden Sie wahrscheinlich perldoc
verwendet haben,
um die verschiedenen Teile der Perl-Dokumentation (im POD-Format) online
einzusehen.
POD ist keine vollständige Textformatiersprache wie troff, LaTeX oder HTML. Wenn Sie also Ihre Skripts mit einer Unmenge an aufwendig formatierten Dokumentationen versehen wollen, sind Sie besser beraten, wenn Sie auf ein anderes Format zurückgreifen und Ihre Dokumentationsdateien getrennt von Ihren Skripts halten. POD-Dateien haben jedoch im allgemeinen den Vorteil, dass sie auf verschiedenen Plattformen und mit verschiedenen Systemen gelesen werden oder en passant in andere geläufigere Formate konvertiert werden können.
Beispiele für POD-Texte finden sich in fast jedem öffentlich verfügbaren Skript oder Modul, das mit Perl ausgeliefert wird oder aus dem CPAN heruntergeladen werden kann. Wenn Ihnen die nachfolgenden Ausführungen zu den POD-Dateien nicht genügen, finden Sie weitere Informationen in der perldoc-Manpage.
POD-formatierter Text besteht aus Befehlsabsätzen und normalen Absätzen. Befehlsabsätze enthalten einfache Formatierungsanweisungen und etwas Text. Normale Absätze enthalten den eigentlichen Text. Sie können aber auch Befehle zur Zeichenformatierung in die normalen Absätzen mit aufnehmen.
Befehlsabsätze stehen in eigenen Zeilen und beginnen mit einem Gleichheitszeichen. Einige Befehlsabsätze weisen auch Text auf, der sich direkt an den Namen des Absatzes anschließt. Das Ende eines Befehlsabsatzes bildet eine leere Zeile.
Für Überschriften verwenden Sie die Befehlsabsätze =head1
und =head2
, denen sich
direkt der Text für die Überschrift anschließt. Diese Überschriften entsprechen in etwa
den Tags <H1>
und <H2>
in HTML oder dem .SH
-Tag in troff
oder nroff
.
Für Listen und andere eingerückte Elemente gibt es die Befehle =over
, =item
und
=back
. Mit =over
beginnen Sie eine Liste, wobei eine optionale Zahl angibt, um wie
viele Leerzeichen die Liste eingerückt werden soll. Jedes Listenelement beginnt mit
einem =item
-Tag und einem optionalen Zeichen, das das Symbol oder die Zahl vor
diesem Element darstellt (Sie müssen sich selbst um die Numerierung kümmern, da
diese nicht automatisch erfolgt). Am Ende der Liste heben Sie die mit =over
eingeleitete Einrückung mit =back
wieder auf.
Normale Absätze werden als einfache Absätze eingegeben, ohne sie mit
irgendwelchen Befehlen zu kennzeichnen. Absätze, die ohne Whitespace-Zeichen
beginnen, werden in der Regel so formatiert, dass sie die Seitenbreite füllen (wie <P>
in HTML). Absätze mit einer Einrückung am Anfang werden unverändert
übernommen (wie <PRE>
in HTML). Alle Absätze müssen mit einer leeren Zeile enden.
In den Absätzen können Sie Zeichenformatierungscodes und Links mit aufnehmen, um ein bestimmtes Wort hervorzuheben oder einen Link einzufügen (der zu einer anderen Perl-bezogenen Manpage wie perlfunc oder ähnlichem führt). Im folgenden sehen Sie einige der geläufigeren Zeichenformate:
I<text>
gibt das Wort text
kursiv aus.
B<text>
gibt das Wort text
fett aus.
C<text>
faßt text
als Code auf.
&escape
; ersetzt den Escape-Code durch ein Sonderzeichen. Die Escape-Codes
sind mit den HTML Escape-Codes für Akzente und andere Sonderzeichen
weitgehend identisch.
E<escape>
; identisch mit &escape
.
L<manpage>
erzeugt einen Link (oder einen textuellen Querverweis) auf eine
Manpage; so erzeugt zum Beispiel L<perlfunc>
eine Verbindung zu der perlfunc-
Manpage. Sie können auch einen Link zu einem speziellen Abschnitt in einer
Manpage herstellen.
Um Text einzubetten, der in einer anderen Formatiersprache formatiert vorliegt - zum
Beispiel HTML oder troff - gibt es ebenfalls Befehle: =for
, =begin
und =end
. Text,
der für bestimmte Formatiersprachen formatiert wurde, wird von dem speziellen
Übersetzer unverarbeitet ausgegeben (der Übersetzer pod2html
wird zum Beispiel
formatiertes HTML direkt in die Ausgabe kopieren) und ansonsten einfach ignoriert.
Verwenden Sie eingebettete Formatierungen, um in speziellen Fällen eine
eingeschränkte Formatierung vorzunehmen.
Sie können POD-formatierten Text sowohl in einer eigenen Datei (in der Regel als
Datei mit der Extension .pod
) speichern oder ihn in Ihre Skript-Dateien integrieren,
wo er schnell geändert und aktualisiert werden kann.
Um POD-Text in ein Skript aufzunehmen, markieren Sie den Anfang des POD-
Textes mit einem beliebigen POD-Befehl (normalerweise =head1
, obwohl auch =pod
den Anfang eines POD-Textes anzeigen kann). Schließen Sie den POD-Text mit =cut
ab. Auf diese Weise teilen Sie Perl mit, wann die Unterbrechung zu Ende ist und der
Text weiter nach Code geparst werden kann.
POD-Text wird in der Regel am Anfang oder am Ende eines Skripts eingefügt. Sie
können ihn aber auch irgendwo an einer beliebigen Stelle in Ihr Skript einfügen, zum
Beispiel um das Verhalten einer Subroutine direkt über dem Code der Subroutine zu
beschreiben. Solange Sie Ihren POD-Text mit einem Befehlsabsatz und =cut
starten
und enden, hat Perl keine Probleme damit.
Wenn Sie einen POD-Text an das Ende einer Datei setzen und eine __END__
-
Markierung verwenden (wie es zum Beispiel beim Erzeugen von Modulen vorkommt),
müssen Sie darauf achten, dass eine Leerzeile nach dem __END__
kommt.
Ein weiteres nützliches Feature von Perl, das anderen Sprachen abgeschaut wurde, ist
die Fähigkeit, einen String zur Laufzeit des Skripts als Perl-Code aufzufassen und
auszuführen. Bewerkstelligt wird dies durch die Funktion eval
, die einen String oder
Block als Argument übernimmt und den darin enthaltenen Perl-Code kompiliert und
ausführt, so als wenn er in einer Datei stehen oder als Perl-Einzeiler ausgeführt würde
- und das alles innerhalb eines gerade laufenden Perl-Skripts.
Warum ist diese Funktion so nützlich? Aus einer Vielzahl von Gründen. Einer davon
ist, dass Sie damit anspruchsvolle Strukturen und Funktionsaufrufe aufbauen können,
ohne extensiv in if-else
-Anweisungen verzweigen zu müssen: Stellen Sie den
aufzurufenden Code aus aneinandergehängten Strings zusammen, und rufen Sie dann
eval
auf, um den String auszuführen. Es ist auch möglich, andere Dateien, die Perl-
Code enthalten, von einem Perl-Skript aus einzulesen und auszuführen - ähnlich der
Funktionsweise von use
und require
, jedoch immer zur Laufzeit Ihres Skripts (genau
genommen ist require
semantisch identisch mit eval
, plus einigen Extraoptionen
zum Suchen und Neuladen von Dateien). Des weiteren ist es möglich, Code bei
Bedarf en passant auszuführen - der Perl-Debugger macht zum Beispiel in seiner
Option zur Codeausführung davon Gebrauch. Oder Sie könnten mit Hilfe von eval
einen Interpreter für Ihre eigene Sprache schreiben.
Mit Hilfe der eval
-Funktion von Perl kann man Code vor der eigentlichen Ausführung
testen und anschließende Fehler und ungewöhnliche Bedingungen, die aus der
Ausführung des Codes resultieren, abfangen. Diese Möglichkeit wird in anderen
Sprachen oft als Ausnahmenbehandlung bezeichnet. Wenn Sie zum Beispiel testen
möchten, ob eine bestimmte Perl-Funktion - zum Beispiel fork
- auf dem aktuellen
System zur Verfügung steht, könnten Sie innerhalb von eval
ein einfaches Beispiel
ausprobieren, schauen, ob es funktioniert, und wenn ja, mit dem Skript und fork
fortfahren. Scheitert eval
, führen Sie einen alternativen Code aus. Die
Ausnahmebehandlung mit eval
ermöglicht eine robustere Fehlerprüfung und -
behandlung in Ihren Skripts.
Eine Beschreibung von eval
finden Sie in der perlfunc-Manpage.
Unter Internationalisierung, manchmal auch I18N genannt, versteht man die Verallgemeinerung von Skripts oder Programmen, so dass diese leicht in eine andere Sprache oder einen Dialekt übertragen oder übersetzt werden können. Von Lokalisierung, L10N, spricht man, wenn man eine internationalisierte Version eines Skripts nimmt und in einer speziellen Sprache zum Laufen bringt. Die Internationalisierung beginnt mit einfachen Maßnahmen - zum Beispiel alle Textstrings, die ein Skript verwendet, separat aufzubewahren, um diese ohne Änderungen am Perl-Code übersetzen zu können. Andere Dinge - die Arbeit mit anderen Zeichensätzen als dem Englischen ABC, die Verwendung anderer Sortier- und Vergleichsfunktionen für Texte, das Formatieren von Zahlen - können über die Verwendung des Lokale-Moduls von Perl gesteuert werden.
Weitere Informationen zur Anwendung und Verwaltung von Perl-Lokalen zur Erzeugung internationalisierter (oder lokalisierter) Skripts finden Sie in der perllocale- Manpage.
Angenommen Sie schreiben ein Perl-Skript, das von Menschen ausgeführt wird, die Sie nicht kennen und denen Sie auch nicht besonders trauen - zum Beispiel wenn Sie eine Multi-User-Unix-Maschine verwalten oder wenn Ihr Skript für CGI verwendet wird. Da Sie denjenigen, der Ihr Skript ausführt, nicht kennen, könnte diese Person theoretisch feindliche Absichten hegen und Ihr Skript nutzen, um auf irgendeinem Weg autorisierten Zugriff auf Ihr System zu erhalten oder es in irgendeiner Weise zu mißbrauchen oder zu schädigen.
Wie können Sie verhindern, dass ein bösartiger Benutzer Ihr Skript mißbraucht oder
Schaden anrichtet? Sorgfältige Programmierung ist eine Möglichkeit - zum Beispiel
vorher prüfen, ob eine Eingabe irgendwelche heiklen Daten enthält, bevor sie einem
system
-Funktionsaufruf oder schrägen Anführungszeichen übergeben wird. Doch
manchmal ist es schwierig, zu entscheiden, welche Daten unsicher sind, manchmal
vergißt man, diese Prüfungen durchzuführen. In all diesen Fällen ist der Taint-Modus
sehr hilfreich.
Der Taint-Modus wird in Perl mit der Option -T
aktiviert. (Er wird außerdem
automatisch ausgeführt, wenn sich die Benutzer- oder Gruppen-ID des Skripts von der
Benutzer- oder Gruppen-ID der Person unterscheidet, die das Skript ausführt - zum
Beispiel setuid-Skripts auf Unix-Systemen). Ist der Taint-Modus aktiviert, überwacht
Perl die Daten, die in Ihr Skript gelangen - aus der Umgebung, als
Befehlszeilenargumente oder als Daten von einem Datei-Handle (einschließlich der
Standardeingabe). Wenn Sie versuchen, diese Daten dazu zu nutzen, irgend etwas
außerhalb Ihres Skripts zu manipulieren, bricht Perl sofort ab. Um diese Daten
trotzdem zu nutzen, müssen Sie Ihr Skript so schreiben, dass diese Daten teilweise
geändert oder extrahiert werden - wodurch verhindert wird, dass unerwartete Daten
unbemerkt durch das Skript hindurchrutschen.
Mit anderen Worten, der Taint-Modus ist kein eigener Sicherheitsmechanismus, aber er zwingt Sie, beim Schreiben Ihres Codes die Sicherheit immer im Auge zu behalten. Wenn Ihre Skripts zum Beispiel in einer unsicheren Umgebung ausgeführt werden, kann der Taint-Modus Ihnen helfen, sicherzustellen, dass Ihre Skripts nicht zu einladenden Sicherheitslecks in Ihrem System werden.
Weitere Informationen zum Taint-Modus und zur Sicherheit in Perl finden Sie in der
perlsec-Manpage. Wenn Sie allgemeinere Auskünfte zum Thema Sicherheit und CGI
benötigen, schauen Sie doch mal in den häufig gestellten Fragen (FAQs) zur Sicherheit
im WWW unter http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html
nach.
Wenn Ihnen speziell die Sicherheit Ihrer Skripts am Herzen liegt, sollten Sie Penguin aus dem CPAN ausprobieren. Penguin stellt eine Umgebung bereit, mit der es möglich ist, Codefragmente zu verschlüsseln und digital zu signieren, bevor sie an andere Sites verschickt werden. Am Zielort entschlüsselt Penguin diese Daten wieder und prüft die Zuverlässigkeit dieses Codes vor seiner Ausführung. Und selbst dann führt Penguin den Code noch innerhalb streng kontrollierter Grenzen aus. Betrachten Sie Penguin einfach als ein Gegenstück zu Javas Mechanismus zum Signieren von Applets und der anschließenden Ausführung innerhalb eines geschlossenen, sicheren »Sandkastens«. Im CPAN finden Sie ausführliche Informationen über Penguin.
PerlScript - Teil der ActiveState-Version von Perl für Windows - ist eine Skripting- Maschine für ActiveX-Komponenten. Mit PerlScript können Sie Perl als Skript- Sprache in jeden ActiveX-Skripting-Host verwenden - zum Beispiel im Internet Explorer, IIS oder in einem beliebigen Webserver oder sogar im Windows Scripting Host (WHS) von Microsoft selbst.
Microsofts Skripting-Maschinen für ActiveX-Komponenten unterstützen per Vorgabe VBScript- und JavaScript-Skripting-Maschinen. Diese Sprachen sind zwar für die meisten Zwecke vollkommen ausreichend, doch kann Ihnen Perl in vielen Fällen weitere und leistungsstärkere Optionen bieten. Außerdem ist es für Programmierer, die bereits mit Perl vertraut sind, ein unschätzbarer Vorteil, wenn Sie einfach mit Perl weiterarbeiten können, anstatt zu anderen Sprachen wechseln zu müssen.
Sie können mit PerlScript auch für das Web programmieren und Perl-Skripts in Webseiten einbetten, und das sowohl clientseitig (Webbrowser) als auch serverseitig (Webserver) - so wie man ansonsten JavaScript- und VBScript-Skripts oder ASP- Seiten (Active Server Pages) nutzt.
PerlScript läßt sich auch mit dem Windows Scripting Host verwenden. Dadurch haben
Sie die Möglichkeit, verschiedene Aspekte des Windows-Systems über Skripts zu
steuern (dient als Ersatz für die alten DOS-Batch-Dateien). Zur Zeit gibt es den
Windows Scripting Host standardmäßig nur zusammen mit Windows 98. Er läßt sich
aber für Windows 95 und Windows NT von msdn.microsoft.com/scripting
herunterladen und installieren.
PerlScript wird automatisch mit der ActiveState-Version von Perl für Windows installiert. Sie können es aber auch als eigene Komponente von der ActiveState- Webseite herunterladen (Sie müssen allerdings eine Version von Perl für Windows installiert haben).
Weitere allgemeine Informationen zu ActiveX-Skripting finden Sie unter http://
msdn.microsoft.com/scripting
. Details zu PerlScript lassen sich in der
Dokumentation zu PerlScript unter http://www.activestate.com/activeperl/docs/
perlscript.html
oder in dem ausgezeichneten »Complete Guide to PerlScript«
(vollständiger PerlScript-Führer) von Matt Sargeant unter http://
www.fastnetltd.ndirect.co.uk/Perl/Articles/PSIntro.html
nachlesen.
Eine Perl-Erweiterung ist ein Weg, eine externe Bibliothek, in der Regel in C
geschrieben, in Perl-Skripts einzubinden. Wenn Sie eine Perl-Erweiterung erzeugen,
erzeugen Sie sozusagen einen speziellen Code, der es Ihnen ermöglicht, diese externe
Bibliothek wie ein beliebiges Perl-Modul mit use
in Ihre Perl-Skripts zu importieren.
Wenn Sie genau hinschauen, werden Sie feststellen, dass viele der Perl-Module im
CPAN sowohl Perl-Code als auch Perl-Erweiterungen verwenden.
Für die Erzeugung einer Perl-Erweiterung müssen Sie eine Sprache namens XS
verwenden, die den »Kleber« zwischen Perl und C bereitstellt (Perl-Erweiterungen
werden in Anlehnung an die XSUB
-Funktion in der XS-Sprache manchmal auch
XSUBs genannt). Sie können XS-Dateien selbst schreiben oder sie aus einer
bestehenden C-Bibliothek erzeugen. Außerdem gibt es besondere Make-Dateien, die
erstellt oder erzeugt werden müssen, damit am Ende alles zusammenpaßt (eine Make-
Datei ist ein Skript, das verwendet wird, um ein Projekt zu kompilieren und die
Abhängigkeiten zwischen mehreren Dateien eines Projekts zu verwalten).
In der Perl-Distribution findet sich eine Reihe von Tools und Modulen, die das
Entwikkeln von Perl-Erweiterungen vereinfachen - einschließlich Tools, um durch
Erzeugung von XS-Dateien bestehende C-Bibliotheken in Perl einzubinden oder um
C-Code aus XS-Dateien zu erzeugen. Besonders erwähnenswert sind in diesem
Zusammenhang die Module des ExtUtils
-Pakets, besonders ExtUtils::MakeMaker
(die Ihnen helfen, Make-Dateien zu erzeugen).
Bevor Sie damit beginnen, Perl-Erweiterungen zu erzeugen, sollten Sie über
ausreichend Hintergrundwissen zu der Entwicklung von Perl-Modulen verfügen.
Dieses Hintergrundwissen können Sie sich in der perlmod-Manpage aneignen. Eine
Einführung in die Erzeugung von Erweiterungen finden Sie in der perlxstut-Manpage.
Des weiteren sollten Sie einen Blick in perlxs (das XS-Referenzhandbuch), h2xs (ein
Skript zum Konvertieren von C-Headerdateien in XS-Dateien) und perguts (für
interne Perl-Funktionen) werfen. Die POD-Dateien in den verschiedenen ExtUtils
-
Modulen enthalten Erläuterungen, wie diese Module anzuwenden sind.
Perl 5.005 wurde während der Arbeit an diesem Buch herausgebracht. Ich habe mich bemüht, auf alle Unterschiede und neuen Teile von Perl hinzuweisen, die für Ihre Arbeit mit der neuen Version von Bedeutung sein könnten. Für den Großteil von Perl sind allerdings nur geringfügige Unterschiede zwischen der Perl-Version 5.005 und der früheren Version 5 zu verzeichnen. Radikale Änderungen sollten Ihnen eigentlich nicht auffallen. Wenn Sie aber bereits über Perl 5.005 verfügen und gern etwas herumspielen wollen, finden Sie in dieser Version eine Reihe von neuen Optionen. Einige davon, die bisher im Buch noch keine Erwähnung fanden, möchte ich Ihnen kurz vorstellen.
Die wahrscheinlich bedeutendste Änderung in Perl 5.005 ist der Einsatz von
Threading. Rufen Sie sich dazu noch einmal Kapitel 18, »Perl und das
Betriebssystem«, in Erinnerung. Dort habe ich die fork
-Funktion und den Einsatz von
Prozessen behandelt und allgemein konstatiert, dass die Prozeßfähigkeiten der Unix-
Version von Perl sich nur schwer auf andere Plattformen übertragen lassen.
Threading soll dieses Problem jetzt lösen. Sie können damit mehrere gleichzeitig
laufende Threads erzeugen, die unabhängig voneinander gestartet und gestoppt
werden können. Wichtiger noch ist jedoch die Tatsache, dass Threading in der Perl-
Sprache plattformübergreifend unterstützt wird, was bedeutet, dass ein für Unix
geschriebenes komplexes Skript mit mehreren Threads sich genausogut unter
Windows oder auf einem Macintosh-Rechner ausführen läßt. Perls Thread-System ist
in dem Thread-Modul definiert, das man einbinden muss, um mit Threads arbeiten zu
können. Beachten Sie, dass sich die Thread-Unterstützung noch im Beta-Stadium
befindet - mit anderen Worten, sie kann Fehler aufweisen und Schwierigkeiten in der
Anwendung bereiten. Außerdem muss man davon ausgehen, dass die Thread-
Unterstützung in zukünftigen Versionen von Perl noch etliche Änderungen erfahren
wird. Informieren Sie sich auf alle Fälle in der POD-Dokumentation, die bei dem
Thread-Modul dabei ist.
Eine zweite bedeutsame Änderung ist die Integration eines Perl-Compilers. Der Compiler, mit Namen perlcc, kann ein Perl-Modul in eine native Bibliothek konvertieren/kompilieren oder ein Perl-Skript in C-Code konvertieren und diesen Code in eine ausführbare Datei kompilieren. Genau genommen ist perlcc das Front- End zu einer generischen Kompilierendstufe in Perl (die Module B und O), mit der Sie Perl-Skripts in quasi alles konvertieren oder kompilieren können.
Perl 5.005 enthält außerdem eine neue Maschine für reguläre Ausdrücke, die
selbsttätig etliche Fehler behebt und einige Neuheiten aufweist. Um die Performance
zu verbessern, können Sie reguläre Ausdrücke außerdem mit dem neuen C
-Operator
vorkompilieren. Weitere Informationen hierzu finden Sie in den Manpages perlre und
perlop.
Da dieses ganze Kapitel ein einzig großer Vertiefungsabschnitt ist, gibt es eigentlich
nicht allzuviel in diesem Abschnitt zu sagen. Deshalb möchte ich Sie an dieser Stelle
noch einmal auf folgendes aufmerksam machen: Wenn Sie Probleme, Fragen oder
Schwierigkeiten haben oder einfach nur wissen wollen, wie sich ein bestimmter Perl-
Teil verhält - von den elementaren Operatoren über die regulären Ausdrücken und
die Referenzen bis zu den Modulen -, sollten Sie neben der Perl-Dokumentation
(Manpages und POD-Dateien) auf alle Fälle die häufig gestellten Fragen (FAQs) zu Perl
zu Rate ziehen. Das Kamelbuch (Programmieren mit Perl, das ich am Tag 1 im
Vertiefungsabschnitt erwähnt habe) kann Ihnen helfen zu verstehen, wie sich Perl in
verschiedenen Situationen verhält. Und wenn Sie trotzdem immer noch festhängen,
nutzen Sie das Web - www.perl.com
, www.activestate.com
(für Windows) und viele
der anderen Websites, die ich im Laufe dieses Buches erwähnt habe, können Ihnen
dabei behilflich sein. Schließlich gibt es noch eine Reihe von Newsgroups (wie die
comp.perl
-Hierarchie - insbesondere comp.perl.misc
) und Mailing-Listen, über die
Sie andere Perl-Programmierer kontaktieren können.
Heute ist der Tag, an dem wir alle losen Enden zusammenbinden. So haben wir heute eine Reihe von zusätzlichen Perl-Elementen betrachtet, die ich aus Zeit- und Platzgründen in keinem der anderen 19 Kapiteln unterbringen konnte. Dieses Mischmasch umfaßt:
eval
Meinen Glückwunsch! Jetzt bleibt uns nur noch ein Tag, und der ist ganz den Beispielen gewidmet. Sie haben Perl in ausreichendem Umfang kennengelernt, um einige aufregende Dinge zu machen. Also nur zu! Und vergessen Sie nicht - Perl ist ein Gemeinschaftsprodukt. Nutzen Sie die Module im CPAN. Und sollten Sie selbst etwas schreiben, von dem Sie meinen, dass auch andere es gebrauchen könnten, stellen Sie es doch auch in das CPAN.
Frage:
Meine Einzeiler funktionieren nicht in MacPerl.
Antwort:
Stellen Sie im Dialog Edit->Preferences->Scripts
sicher, dass Sie die Option
Run Scripts Opened from Finder
markiert haben. Wenn Sie hier Edit
ausgewählt haben, lassen sich Ihre Einzeiler nicht ausführen.
Frage:
Meine Einzeiler funktionieren nicht unter Windows.
Antwort:
Es gibt Unterschiede zwischen den Anführungszeichen in der DOS/Windows-
Befehlszeile und in Unix. Unter Unix können Sie einfache und doppelte
Anführungszeichen verwenden, unter Windows nur doppelte. Deshalb sollten
Sie sich vergewissern, dass Ihre Einzeiler unter Windows vorn und hinten in
doppelten Anführungszeichen stehen und alle Anführungszeichen im Skript
selbst mit einem Backslash markiert sind.
Frage:
Meine Einzeiler funktionieren nicht in Unix.
Antwort:
Sie funktionieren nicht? Haben Sie das Skript auch wirklich in eine Zeile
eingegeben, ohne Return-Zeichen? Haben Sie auch nicht vergessen, das
gesamte Skript in einfache Anführungszeichen zu setzen? Haben Sie an die
Perl-Option -e
gedacht? Wenn Sie alle diese Punkte überprüft haben, stellen
Sie sicher, dass Sie das gleiche Skript ausführen können, wenn Sie es in einer
Datei abspeichern.
Frage:
Aus Ihrer Beschreibung entnehme ich, dass Perl die OOP-Konzepte der
öffentlichen (public) und privaten (private) Daten nicht unterstützt. Was sollte dann
jemand daran hindern, Methoden zu verwenden, die nicht als Teil der öffentlichen
API ihrer Klasse gedacht sind?
Antwort:
Nichts. Das objektorientierte Modell von Perl unterscheidet nicht zwischen
privater und öffentlicher API. Es geht davon aus, dass Sie und die
Programmierer, die Ihre Klassen verwenden, sich anständig verhalten, was die
API angeht. Als Entwickler einer Klasse sollten Sie Ihre API dokumentieren
und angeben, welche Ihrer Methoden öffentlich sind (dazu eignet sich POD
sehr gut), und dann davon ausgehen, dass alle, die Ihre Klasse verwenden,
sich auch an diese Vorgaben halten. Umgekehrt sollten auch Sie, wenn Sie die
Klassen anderer Programmierer verwenden, sich an deren dokumentierte
öffentliche API halten und interne Methoden oder Daten nur verwenden,
wenn Sie genau wissen, was Sie tun (und das Risiko zu tragen bereit sind).
Frage:
Mehrfachvererbung ist sehr verwirrend und fehleranfällig. Warum hat sich Perl
nicht auf die einfache Vererbung beschränkt?
Antwort:
Um damit die Mächtigkeit der Sprache zu beschränken? Es sollte Ihnen an
dieser Stelle im Buch bereits aufgefallen sein, dass Perl zu keiner Zeit wirklich
versucht, den Programmierer in seiner Arbeit Grenzen zu setzen.
Mehrfachvererbung mag zwar oft verwirrend und auch schwierig zu debuggen
sein, aber sie ist auch unglaublich leistungsstark, wenn Sie zusammen mit
einem guten Design verwendet wird (und vergessen Sie nicht, ein gutes
Design bedingt nicht unbedingt Vererbung). Die Entwickler von Perl lassen
Ihnen lieber genug Seil, um sich aufzuhängen, als dass sie Sie zu knapp
halten, so dass Sie letztlich nicht genug Seil haben, um einen Knoten zu
binden.
Frage:
Wo, zum Teufel, kommen die Begriffe I18N und L10N her?
Antwort:
Es stehen jeweils 18 Buchstaben zwischen dem I und dem N in dem Wort
»Internationalization« (Internationalisierung) und 10 Buchstaben zwischen
dem L und dem N in »Localization« (Lokalisierung). Internationalization und
Localization sind wirklich sehr lange Wörter. Programmierer mögen das
nicht.
Frage:
Ihre Beschreibung der Perl-Extensionen erläutert, wie man C-Code aus einem
Perl-Skript heraus aufruft. Wie ruft man Perl-Code von einem C-Programm aus
auf?
Antwort:
Schlagen Sie in der perlcall-Manpage nach. Außerdem müssen Sie sich in der
XS-Sprache auskennen und wissen, wie man Erweiterungen konstruiert.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.
-e
-i
-p
eval
? Wozu verwendet man sie?
perl -p 's/t/T/q';
perl -ne 'print 'Zeile: ', reverse $_;';
EinfacheKlasse
, die drei Instanzvariablen
enthält: a
, b
und c
. Nehmen Sie folgende Methoden mit auf:
new
-Konstruktor, um die Variablen a
, b
und c
zu erzeugen und zu
initialisieren.
a
, b
und c
auszugeben und zu ändern.
Implementieren Sie diese, wie Sie wollen.
a
, b
und c
auszugeben. Vergewissern Sie
sich, dass a
, b
und c
Zahlen enthalten; geben Sie andernfalls Fehlermeldungen
aus.
Hier die Antworten auf die Workshop-Fragen aus dem vorigen Abschnitt.
-e
führt ein Perl-Skript (einen Einzeiler) von der Befehlszeile aus.
-i
bearbeitet Dateien. Das bedeutet, das Ergebnis des Skripts wird in
der Originaldatei gespeichert. Wird der Option -i
eine Dateiextension als
Argument mitgegeben, wird diese verwendet, um eine Sicherungsdatei der
Originalversion der Datei zu erstellen.
-p
bettet den Perl-Einzeiler in eine while
-Schleife (<>
) mit einer print
-
Anweisung am Ende ein. Wenn Sie die Zeilen einer Datei einzeln bearbeiten und
dann ausgeben wollen, sollten Sie diese Option verwenden, um sich Tipparbeit zu
ersparen.
methode $obj,1,2,3;
$obj->methode(1,2,3);
format
eine Formatschablone definieren und das Ergebnis mit write
ausgeben.
troff
konvertiert werden kann.
eval
wird verwendet, um Perl-Codefragmente en passant während
der Ausführung eines Skripts auszuwerten. Sie können eval
dazu nutzen, um
andere Skripts in Ihr aktuelles Skript aufzunehmen oder Codeabschnitte zu testen,
bevor Sie sie richtig ausführen lassen.
-T
. Der Modus wird allerdings auch automatisch eingeschaltet, wenn
sich die Benutzer- oder Gruppen-ID des Skripts von der Benutzer- oder Gruppen-
ID der Person unterscheidet, die das Skript ausführt (ist beispielsweise für CGI-
Skripts, die auf einem Webserver ausgeführt werden, der Fall).
fork
zu bewerkstelligen. Aber mit der Verwendung von fork
waren Ihre Skripts
nicht mehr auf andere Plattformen portierbar. Durch Threads wurde das Problem
jetzt gelöst.
perl -e ' while (<>){while (/t/g){$c++;}};print $c;' datei.txt
perl -e 'while(<>){$sum+=$_;}print "$sum\n";'
perl -pe -i.bak 's/ /\t/g' ozy.txt
-e
fehlt.
reverse
. Dieser Einzeiler erweckt den
Eindruck, dass die einzelnen Eingabezeilen zeichenweise in umgekehrter
Reihenfolge mit dem Wort »Zeile« am Anfang ausgegeben werden. Sie sollten sich
jedoch in Erinnerung rufen, dass die reverse
-Funktion je nach Kontext (Skalar-
oder Listenkontext) ein unterschiedliches Verhalten aufweist. In diesem Falle wird
reverse
in einem Listenkontext aufgerufen, da die Argumente zu print
immer
eine Liste oder eine Kombination von Listen sind. Doch damit wird nur die
Reihenfolge der Zeilen in einem Array umgedreht. Das Argument $_
wird dann in
eine Liste konvertiert, diese Liste mit einer Zeile umgedreht und anschließend
ausgegeben. Mit anderen Worten, äußerlich passiert nichts.
reverse
-Funktion in
einem skalaren Kontext aufrufen. Dieser Fehler kann schnell mit der scalar
-
Funktion behoben werden:
perl -ne 'print 'Zeile: ', scalar (reverse $_);'
reverse
umzudrehen und ihn dann mit dem frisch angehängten Neue-Zeile-
Zeichen wieder auszugeben:
perl -ne 'chomp;print "Zeile: ", scalar(reverse $_), "\n" ; '
-l
. Damit wird das Neue-Zeile-Zeichen von der Eingabe entfernt, um
es (oder irgendein anderes Zeilenende-Zeichen Ihrer Wahl) hinterher für Sie
wieder anzuhängen:
perl -lne 'print "Zeile: ", scalar(reverse $_);'
a
, b
oder c
heißt).
#!/usr/bin/perl -w
package EinfacheKlasse;
sub new {
my ($classname, $a, $b, $c) = @_;
my $self = {};
$self->{a} = $a;
$self->{b} = $b;
$self->{c} = $c;
return bless $self, $classname;
}
# der längste Weg
sub getA {
my $self = shift;
return $self->{a};
}
sub setA {
my $self = shift;
if (@_) {
$self->{a} = shift;
} else {
warn "kein Argument; verwende undef\n";
$self->{a} = undef;
}
}
# ein etwas allgemeinerer Weg, der mehr Argumente benötigt.
sub get {
my ($self, $var) = @_;
if (!defined $var) {
print "Keine Variable!\n";
return undef;
} elsif (!defined $self->{$var}) {
print "Variable nicht definiert oder ohne Wert.\n";
return undef;
} else {
return $self->{$var};
}
}
sub set {
my ($self, $var, $val) = @_;
if (!defined $var or !defined $val) {
print "Brauche Variable und Wert als Argument!";
return undef;
} else {
$self->{$var} = $val;
return $val;
}
}
# ein wirklich allgemeiner Weg
sub AUTOLOAD {
my $self = shift;
my $var = $AUTOLOAD;
$var =~ s/.*:://;
$var =~ s/[gs]et//;
$var = lc $var;
if (@_) {
$self->{$var} = shift;
return $self->{$var};
} else {
return $self->{$var};
}
}
sub sum {
my $self = shift;
my $sum = 0;
foreach ('a','b','c') {
if (!defined $self->{$_} or $self->{$_} !~ /^\d+/ ) {
warn "Variable $_ enthaelt keine Zahl.\n";
} else { $sum += $self->{$_}; }
}
return $sum;
}
package main;
$obj = new EinfacheKlasse (10,20,30);
print "A: ", $obj->getA(), "\n";
$obj->setA("foo");
print "A: ", $obj->getA(), "\n";
print "B: ", $obj->get('b'), "\n";
$obj->set('b', 'bar');
print "B: ", $obj->get('b'), "\n";
# es gibt keine getC-Methode; autoload
print "C: ", $obj->getC(), "\n";
$obj->setC('baz'); # ditto setC
print "C: ", $obj->getC(), "\n";
# zurücksetzen
print "\nA: 10\n";
$obj = new EinfacheKlasse (10);
print "Summe: ", $obj->sum(), "\n";
print "\nA: 10 B: 5\n";
$obj = new EinfacheKlasse (10,5);
print "Summe: ", $obj->sum(), "\n";
print "\nA: 10 B: 5 C: 5\n";
$obj = new EinfacheKlasse (10,5,5);
print "Summe: ", $obj->sum(), "\n";