Per 5 Tutorial - Der Computerkurs Teil 2
 

Referenzen

Mir dem type globbing erhält man symbolische Referenzen, dh. sie beinhalten den Namen einer Variablen, vergleichbar mit einem symbolischen Link in einem Unix-Filesystem. In Perl 5 gibt es auch sogenannte harte Referenzen. Sie zeigen direkt auf das der Variabeln zugrundeliegende Objekt, welches eine skalare Variable, ein Array oder ein assoziativer Array (Hash) sein kann, aber auch eine Subroutine oder ein Filehandle. Diese Referenzen sind 'intelligent'. Sie führen Buch über die Anzahl Referenzen auf ein Objekt und geben das Objekt frei, sobald diese Anzahl auf Null geht.
Eine Variable wird von Perl nie implizit dereferenziert. Falls eine skalare Variable eine Referenz ist, wird sie sich immer als skalare Variable verhalten und nicht als der Typ, den sie referenziert. Diese Tatsache hat syntaktische Konsequenzen (siehe perldsc- , resp. perlLoL- Manpage).

Erzeugen von Referenzen

  1. Mit dem Backslash-Operator:
    $scalarref = \$foo;
    $arrayref  = \@ARGV;
    $hashref   = \%ENV;
    $coderef   = \&handler;
    $globref   = \*STDOUT;
  2. Als Referenz zu einem anonymen Array, Hash oder Funktion:
    $arrayref = [1, 2, ['a', 'b', 'c']];
    
    $hashref = {'Adam' => 'Eve', 'Clyde' => 'Bonnie');
    
    $coderef = sub { print "Boink!" };
  3. Referenzen werden häufig durch spezielle Subroutinen, den Konstruktoren zurückgegeben:
    $objref = new Doggie (Tail => 'short', Ears => 'long');
    $objref->bark();     # Aufruf einer Methode
  4. Referenzen zu Filehandles werden durch Referenzen zu einem Typeglob erzeugt. Folgendes Beispiel zeigt, wie ein Filehandle als Parameter einer Subroutine übergeben wird:
    splutter(\*STDOUT);  #  Aufruf
    sub splutter {       #  Deklaration
        my $fh = shift;
        print $fh "gugus\n";
    }

Dereferenzieren

  1. Ueberall, wo man einen Identifier als Teil eines Variablen- oder Subroutinennamens schreiben würde, kann dieser Identifier durch eine einfache skalare Variable, welche eine Referenz auf den gewünschten Typ darstellt, ersetzt werden.
    $bar = $$scalarref;
    push(@$arrayref, $filename);
    $$arrayref[0] = "Januar";
    $$hashref{"KEY"} = "VALUE";
    &$coderef(1,2,3);
    print $globref "output\n";
  2. Ueberall, wo man einen Identifier als Teil eines Variablen- oder Subroutinennamens schreiben würde, kann dieser Identifier durch einen BLOCK, welcher eine Referenz auf den gewünschten Typ zurückgibt, ersetzt werden.
    $bar = ${$scalarref};
    push(@{$arrayref}, $filename);
    ${$arrayref}[0] = "Januar";
    ${$hashref}{"KEY"} = "VALUE";
    &{$coderef}(1,2,3);

    In diesen Fällen ist es natürlich überflüssig die geschweiften Klammern zu verwenden. Aber da ein Block einen beliebigen Ausdruck beinhalten kann, gibt es vernünftigere Beispiele:

    &{ $dispatch{$index} }(1,2,3);   # Aufruf der korrekten Subroutine
  3. Als syntaktische Variante geht auch:
    $arrayref->[0] = "Januar";
    $hashref->{"KEY"} = "VALUE";

    Die linke Seite vom Pfeil kann irgendein Ausdruck sein, welcher eine Referenz zurückgibt.

    $array[$x]->{"foo"}->[0] = "Januar";

    Vor dieser Anweisung könnte $array[$x] undefiniert sein, wird aber an dieser Stelle automatisch zu einer Referenz auf einen Hash. Dasselbe gilt analog für $array[$x]->{"foo"}. Die Pfeile zwischen den Klammern müssen nicht geschrieben werden:

    $array[$x]{"foo"}[0] = "Januar";
  4. Eine Referenz kann aber auch eine Referenz auf ein Objekt (zu einer Klasse) sein. Dann gibt es vermutlich Methoden, welche durch diese Referenz zugegriffen werden können:
    $obj->methode($param);

    Wir werden im nächsten Kapitel mehr davon hören. Und dann gibt es noch die perlobj-Manpage.


Mit den Referenzen von Perl 5 ist es einfach mehrdimensionale Datenstrukturen (Arrays von Arrays, Arrays von Hashes, Hashes von Subroutinen etc. zu erzeugen (siehe perldsc- resp. perlLoL-Manpage).
Weitere Angaben über Referenzen findet man in den perlref -Manpage.

Referenzen als Parameter von Subroutinen

Manchmal möchte man nicht einen Array als Wertparameter übergeben, sondern innerhalb der Subroutine mit der globalen Variablen arbeiten (PASCAL: VAR-Parameter). Natürlich ist es schneller eine Referenz zu übergeben, anstelle eines ganzen Arrays, daneben ist es die einzige Möglichkeit, mehrere Arrays als Parameter zu übergeben. (Warum?)
Das folgende Beispiel gibt die letzten Elemente von einer Liste von Arrays aus:

@letzte = popmany( \@a, \@b, \@c, \@d );
sub popmany {
    my $aref;
    my @retlist = ();
    foreach $aref (@_) {
        push @retlist, pop @$aref;
    }
    return @retlist;
}

Das ist ja alles sehr schön, aber wie bekomme ich mehrere Arrays oder Hashes als Rückgabewerte? Wie wär's mit folgendem:

($aref, $bref) = func(\@a, \@b);
print "@$aref has more then @$bref\n";
sub func {
    my ($cref, $dref) = @_;
    if (@$cref > @$dref) {
        return ($cref, $dref);
    } else {
        return ($dref, $cref);
    }
}

 


Uebung

Man nehme die Uebung des letzten Kapitels und tausche die Parameter der Subroutine aus. Damit das funktioniert, muss man eine Referenz auf den Array der Textstücke übergeben und in der Subroutine den Array dereferenzieren.

 


Module


Packages

Perl stellt ein Mechanismus zur Verfügung, der es erlaubt, verschiedenen Namensbereiche zu definieren, welche sich nicht überlappen. Dies ist die Grundlage für die Verwendung von Perl-Bibliotheken und für die Entwicklung grösserer Applikationen (Modularisierung). Ausser ein paar speziellen Variablen gibt es in Perl eigentlich keine globalen Variablen, da jeder Variablenname automatisch zum Package main gehört. Man kann mit der package-Anweisung den gewünschten Namensbereich auswählen. Der Gültigkeitsbereich einer package-Anweisung beginnt bei der Anweisung und endet am Ende des umgebenden Blockes. Variablen eines anderen Packages können mit folgender Notation referenziert werden:

$Package::Variable
$Package'Variable   (Notation von Perl V4)

Beispiele:

{
package MyPack;
$foo = 100;
$bar = 'aaa';
$::spe = 'hallo'; # oder $main::spe
}
$foo = 200; $bar = 'bbb';
print $foo, $bar; # 200bbb
print $MyPack::foo, $MyPack::bar; # 100aaa
print $spe; # hallo

Die package-Anweisung wird häufig an den Anfang eines Files gesetzt, welches mit der require-Anweisung von einem anderen File verwendet wird.

Konstruktoren und Destruktoren von Packages

Zwei spezielle Subroutinen werden von Perl als Konstruktoren resp. Destruktoren eines Package interpretiert. Sie heissen BEGIN resp. END.
Sobald BEGIN vollständig definiert ist, wird sie auch ausgeführt, das heisst, bevor der Rest des Files vollständig geparst ist. Damit kann ein BEGIN-Block Definitionen von Subroutinen und ähnlichem von anderen Files importieren und damit dem Parser sichtbar machen.
END wird ganz am Ende, beim Beenden des Interpreters ausgeführt.


Perl-Klassen

Es gibt keine spezielle Syntax für Klassen in Perl. Ein Package kann als Klasse gelten, falls sie Subroutinen zur Verfügung stellt, welche Methoden sind. Ein solches Package kann Methoden von anderen Klassen ableiten, indem sie die Namen dieser Klassen in dem @ISA-Array angibt.

package subclass;
@ISA = (baseclass);
sub new {
    my $self = {};
    bless $self;
    return $self;
}

Weitere Informationen findet man in der perlobj-Manpage.


Module

Ein Modul ist ein Package, welches in einem File mit dem gleichen Namen als Bibliothek abgespeichert ist und so gestaltet ist, dass man es wiederverwenden kann. Das heisst, es kann einen Mechanismus zur Verfügung stellen, der es erlaubt, einige seiner Symbole in das Package, welches es verwendet, zu exportieren.
Es kann aber auch als Klassendefinition aufgefasst werden, die seine Funktionsweise via Methoden zur Verfügung stellt, ohne Symbole explizit zu exportieren.
Oder es kann ein bisschen von beidem sein.

Will man zum Beispiel ein Modul mit dem Namen Gugus definieren, erzeugt man ein File mit dem Namen Gugus.pm und setzt folgende Zeilen an den Anfang dieses Files:

    package Gugus;
    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(func1 func2);
    @EXPORT_OK = qw($hugo @egon %mueller func3);

Der Array @EXPORT beinhaltet die Symbole, welche per default exportiert werden, der Array @EXPORT_OK diejenigen, welche auf Anfrage exportiert werden können.

Perl Module werden mit use aufgerufen:

   use Module;

oder

   use Module LIST;

aufgerufen. Die Liste LIST beinhaltet die gewünschten Symbole, welche in den aufrufenden Namensbereich importiert werden sollen. Dies ist äquivalent zu folgenden Anweisungen:

   BEGIN {require "Module.pm"; import Module; }

resp.

   BEGIN (require "Module.pm"; import Module LIST; }


Alle Perl-Module sollten die Endung '.pm' haben. use nimmt an, dass diese Endung vorhanden ist und ergänzt den Filenamen entsprechend. Schauen wir uns noch ein letztes Beispiel an, welches den Unterschied zwischen use und require aufzeigt:

require "Cwd.pm";       # Cwd::
$here = Cwd::getcwd();
use Cwd;           # Importiere Symbole von Cwd
$here = getcwd();
use Cwd();         # Importiere leere Liste von Cwd
$here = getcwd();  # Fehler: getcwd() nicht bekannt!!
require "Cwd.pm";       # Cwd::
$here = getcwd();  # Fehler: kein main::getcwd()!!

An dieser Stelle ist es vielleicht interessant zu wissen, wo und welche Module auf meinem System vorhanden sind.

% perl -V     # gibt viele Einzelheiten über die Installation an
              # inklusive @INC , den Modul-Suchpfad
% perldoc perldoc  # Modulbeschreibungen

Uebung 1

Wechsle in das Verzeichnis /tmp und lese die Fileliste in einen Array ein und wechsle in das Startverzeichnis zurück. Drucke den Namen des aktuellen Arbeitverzeichnisses vor und nach den Wechseln aus:

Startverzeichnis
# wechseln
Tmp-Verzeichnis
Fileliste
# zurück wechseln
Startverzeichnis

Verwende dazu das Standard-Modul Cwd.pm. Beachte: Es gibt verschiedene Möglichkeiten, den Inhalt eines Verzeichnisses zu lesen:

  • readdir
  • `ls` resp qx{ ls }
  • Pipe von /bin/ls:
    open(FILES,"/bin/ls *|");
    while ($File = <FILES>) {..}

Uebung 2

Mache aus der letzten Uebung ein Modul, welches die Subroutine enthält und verwende ein anderes File für das Hauptprogramm. Im Hauptprogramm wird mit use das Modul importiert. Teste die zwei syntaktischen Varianten

use Module;
use Module LIST;

 


Einführung in Perl 5 Objekte


Viele Leute schrecken vor den praktischen Perl5-Modulen zurück, weil diese mit Objekten zu tun haben. Und das ist ja schon mal verdächtig und tönt nach etwelchen Schwierigkeiten ohne entsprechend nützlich zu sein.

Auf der anderen Seite führen gewisse Probleme automatisch hin zu Objekten. Das macht den Leuten Angst. Unnötigerweise.

Es ist ein riesiger Unterschied genügend über OO-Programmierung zu wissen, um Module zu verwenden , oder um Module selber entwerfen und implementieren zu können. Man befürchtet das letztere können zu müssen um Zugang zum ersteren zu erhalten. Das ist weit weg von der Realität.

Man muss nicht viel wissen um Module verwenden zu können. Man lädt einfach die Library und ruft die dokumentierten "Konstruktoren" auf. "Konstruktoren" sind die Dinge, welche neue Objekte erzeugen. Häufig werden sie new genannt.

In Perl5 werden ein oder zwei neue Konzepte verwendet, welche Sie vielleicht bisher noch nie gesehen haben:

  • Die Anweisung use Module lädt ein Modul mit dem Namen Module.pm (zur Kompilationszeit) und fügt die exportierten Namen in Ihren Namensraum ein. Die Anweisung require Module lädt das Modul ebenfalls, aber erst zur Laufzeit und importiert keine Namen.
  • Der Pfeil-Operator für die Dereferenzierung -> bedeutet ein Aufruf einer Methode (Subroutine) eines Objektes. In OO-Slang sagt man auch 'dem Objekt eine Message senden'. Dabei braucht man keinerlei Kenntnisse über den Aufbau des Objektes. Es ist einfach eine Black Box, welche Subroutinen zur Verfügung stellt. Das ist alles.
  • Die folgenden zwei Zeilen sind aequivalent. Die zweite Zeile ist jedoch syntaktisch ein wenig klarer:
        $obj = new CGI;
        $obj = CGI->new();
    
    
  • Wie jeder andere Unterprogrammaufruf, kann eine Methode irgend etwas zurückgeben, sogar ein anderes Objekt.
       use LWP::UserAgent;
       $ua = new LWP::UserAgent;
       $ua->agent("Mozilla/5.0PlatinumB3");  # hee :-)
    
       $req = new HTTP::Request GET => 'http://perl.com/perl/';
       $req->header('Accept' => 'text/html');
    
       # send request
       $result = $ua->request($req);
    
       # check the outcome
       if ($result->is_success) {
          print $result->content;
       } else {
          print "Error: " . $result->code
                    . " " . $result->message;
       }
    
    

Das wär's. Das ist alles. Mehr braucht man nicht um Module in Perl zu verwenden.

Hier sind noch ein paar Beispiele für den Gebrauch von perl WWW-Modulen:

   use CGI;
   $req = CGI->new();

   use CGI::Imagemap;
   $map = CGI::Imagemap->new();

   use HTML::Parse;
   $html = parse_htmlfile("test.html");

   use URI::URL;
   $url = URI::URL->new('gisle.gif','http://www.com/%7Euser');

   use HTTP::Request;
   $hreq = HTTP::Request->new('GET', 'http://www.perl.com/');

 

last update: 14.9.1998, Roland Dietlicher , Systemdienste/Informatikdienste ETH Zürich

TextArchiv 7 - http://www.ta7.de

 
  Auf dieser Homepage waren bisher 48261 Besucher (103100 Hits) >>> Hits = Klicks  
 
Diese Webseite wurde kostenlos mit Homepage-Baukasten.de erstellt. Willst du auch eine eigene Webseite?
Gratis anmelden