SELFHTML: Perl / Perl-Sprachelemente / Subroutinen
Author: Redaktion SELFHTML, selfhtml81@selfhtml.org
Description: Was Subroutinen in Perl sind, und wie sie definiert werden.
Keywords: SELFHTML, Perl, Subroutinen, Unterprogramme, Funktionen, Rückgabewert, Returnwert, Parameter
Date: 2005-11-09T00:29:27+01:00

| # Subroutinen
| Subroutinen erstellen Subroutinen mit Parametern aufrufen Rückgabewerte bei Subroutinen

## Subroutinen erstellen

Bei komplexeren Perl-Scripts ist es empfehlenswert, bestimmte Programmteile in selbst definierte Unterprogramme oder Funktionen zu verlagern - so genannte Subroutinen. Auf diese Weise können Sie das Script besser strukturieren. Sinnvoll ist das vor allem bei Programmteilen, die im Laufe des Scripts mehrmals ausgeführt werden. Bevor Sie also eine größere Prozedur mehrmals im Script notieren, sollten Sie die entsprechende Prozedur in eine Subroutine stecken und diese Subroutine an der gewünschten Stelle aufrufen.

### Beispiel eines vollständigen CGI-Scripts in Perl:

Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Test</title></head><body>\n";

    my $Ergebnis = 1 + 2 * 3 + 4 * 5 + 6 * 7 + 8 * 9;
    Ausgabe();
    $Ergebnis = sqrt(sqrt(81));
    Ausgabe();

    print "</body></html>\n";

    sub Ausgabe {
     print "Das Ergebnis lautet: <b>$Ergebnis</b><br>\n";
    }

### Erläuterung:

Im Beispiel wird eine Subroutine mit dem Namen `Ausgabe` erstellt. Eine Subroutine beginnt mit dem Schlüsselwort `sub`. Dahinter folgt ein frei wählbarer Name, der den Namenskonventionen von Perl entsprechen muss. Der gesamte Inhalt der Subroutine muss in geschweiften Klammern stehen. Sie können beliebige und beliebig viele Anweisungen innerhalb der Subroutine notieren.

Mit ihrem Namen und runden Klammern dahinter rufen Sie eine Subroutine auf. Der Aufruf ist eine eigene Anweisung, muss also wie andere Anweisungen mit einem Semikolon abgeschlossen werden. Im obigen Beispiel kommt zweimal die Anweisung `Ausgabe();` vor. Dadurch wird die Subroutine mit dem Namen `Ausgabe` aufgerufen.

### Beachten Sie:

Anweisungen in Subroutinen werden nur ausgeführt wenn die Subroutine aufgerufen wird.

Es ist egal, an welcher Stelle im Script eine Subroutine steht. Sie kann im Prinzip überall stehen. Es ist allerdings sinnvoll, alle Subroutinen optisch getrennt vom direkt ausgeführten Hauptprogramm zu notieren.

Beim Aufruf könnten Sie anstelle von `Routine();` auch `&Routine;` oder `&Routine();` notieren. Die erste Art ist jedoch am empfehlenswertesten, vor allem bei Aufrufen ohne Klammern kann es zu Fehlern kommen.

Wenn Sie - wie im obigen Beispiel - mit `use strict;` arbeiten, müssen Sie bekanntlich alle Variablen vor ihrer ersten Verwendung deklarieren. Damit wird aber auch der Geltungsbereich einer Variablen eingeschränkt. Eine Subroutine stellt einen eigenen Block und Geltungsbereich dar. Wenn Sie also beispielsweise innerhalb einer Subroutine mit `my $Variable=1;` eine Variable deklarieren und im Hauptprogramm versuchen, mit `print $Variable` den Inhalt auszugeben, führt dies zu einer Fehlermeldung, da `$Variable` im Hauptprogramm nicht bekannt ist. Umgekehrt ist es anders: Variablen, die im Hauptprogramm deklariert sind, sind auch in Subroutinen verfügbar. Im obigen Beispiel wird ja von dieser Möglichkeit Gebrauch gemacht. Generell ist es auch aus diesem Grund bei größeren Scripts sinnvoll, möglichst viel Code mit Variablendeklarationen in Subroutinen zu packen und im Hauptprogramm so wenig Variablendeklarationen wie möglich zu haben. Denn globale Variablen können tendenziell leichter zu logischen Fehlern im Programmablauf führen, da sie nicht so leicht zu kontrollieren sind wie Variablen in begrenzten Subroutinen.

Das Überschreiben von vordefinierten Perl-Funktionen ist ebenfalls möglich. Wenn Sie zum Beispiel die Funktionsweise einer vordefinierten Funktion ergänzen möchten, definieren Sie einfach eine neue Subroutine mit dem entsprechenden Namen. Einige Perl-Module machen von dieser Möglichkeit Gebrauch. Um auf die ursprüngliche Funktion zuzugreifen, setzen Sie einfach ein `CORE::` vor den Namen.

## Subroutinen mit Parametern aufrufen

Beim Aufruf können Sie einer Subroutine Daten übergeben, die von der Subroutine verarbeitet werden sollen.

### Beispiel eines vollständigen CGI-Scripts in Perl:

Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print "Content-type: text/html\n\n";
    print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n";
    print "<html><head><title>Test</title></head><body>\n";

    formatHTML("Hallo User","h1");
    formatHTML("Dein Browser gibt sich aus als $ENV{HTTP_USER_AGENT}","i");

    print "</body></html>\n";

    sub formatHTML {
     my $Inhalt = shift;
     my $Format = shift;
     print "<$Format>$Inhalt</$Format>";
    }

### Erläuterung:

Das Beispiel definiert eine Subroutine namens `formatHTML`. Im oberen Teil des Scripts können Sie sehen, wie diese Subroutine aufgerufen wird. Mit dem Aufruf `formatHTML("Hallo User","h1");` werden der Subroutine zwei Parameter übergeben. Denn die Subroutine soll die Aufgabe haben, aus einem übergebenen Text und einem übergebenen HTML-Elementnamen ein HTML-Konstrukt, bestehend aus Anfangs-Tag, Inhalt und End-Tag auszugeben.

Die Subroutine erwartet also zwei Parameter. Interessant ist, wie sie die Parameter abfragt. Dazu benutzt sie einfach die Perl-Funktion shift und weist deren Rückgabewert einem Skalar zu. Um diese Anweisung zu verstehen, ist es wichtig zu wissen, dass Parameter, die einer Subroutine übergeben werden, in der vordefinierten Variablen `@_` stehen. Diese Variable enthält die Liste aller Parameter, die der Subroutine übergeben wurden. Der erste Parameter steht dann in `$_[0]`, der zweite in `$_[1]` usw. Eleganter ist es jedoch, sich die Parameter mit der `shift`-Funktion zu holen. Da `shift` beim Aufruf kein Parameter übergeben wird, wendet die Funktion ihre Arbeit automatisch auf die vordefinierte Variable `@_` an. Die Funktion entfernt das erste Element der Liste und gibt es zurück. Durch wiederholtes Aufrufen von `shift` kann sich eine Subroutine also nach und nach alle Parameter abholen, die ihr übergeben wurden.

Die Subroutine im Beispiel holt sich also den ersten Parameter und speichert ihn in `$Inhalt` und den zweiten in `$Format`. Dann erzeugt sie eine `print`-Ausgabe und baut darin das gewünschte HTML-Konstrukt zusammen. Bei jedem Aufruf aus dem Hauptprogramm bewirkt die Subroutine also eine Ausgabe im Browser mit den übergebenen Parametern.

### Beachten Sie:

Sie müssen nirgendwo festlegen, wie viele und welche Parameter eine Subroutine übergeben bekommen kann. Eine Subroutine, die nicht weiß, wie viele Parameter sie übergeben bekommt, kann die übergebene Parameterliste beispielsweise mit einer foreach-Schleife in der Form `foreach(@_)` abarbeiten.

## Rückgabewerte bei Subroutinen

Subroutinen können Werte zurückgeben. Subroutinen, die Parameter übergeben bekommen, damit etwas tun und die verarbeiteten Daten zurückgeben, entsprechen am ehesten dem, was man unter einer Funktion versteht. Die eingebauten Perl-Funktionen folgen diesem Schema, aber auch die meisten Subroutinen, die Sie in Modulen aufrufen können, arbeiten als Funktionen.

### Beispiel eines vollständigen CGI-Scripts in Perl:

Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)

    #!/usr/bin/perl -w

    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    print HTMLKopf();
    print HTMLCode("h1","Hallo!","font-size:24pt; color:red");
    print HTMLCode("p","Wie geht's?","");
    print HTMLFuss();

    sub HTMLKopf {
     my $Kopf = "Content-type: text/html\n\n".
      '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'."\n".
      "<html><head><title>Test</title></head><body>\n";
     return($Kopf);
    }

    sub HTMLFuss {
    my $Fuss = "<hr>\n<script type=\"text/javascript\"><!--\n".
                "document.write(\"URL-Adresse: \"+document.URL);\n//--></script>\n".
                "</body></html>\n";
     return($Fuss);
    }

    sub HTMLCode {
     my $Tag = shift;
     my $Inhalt = shift;
     my $Style = shift;
     unless(defined($Style) and length($Style)) {
      return("<$Tag>$Inhalt</$Tag>");
     }
     else {
      return("<$Tag style=\"$Style\">$Inhalt</$Tag>");
     }
    }

### Erläuterung:

Das Beispiel weitet die Subroutinen-Technik zum Erzeugen von HTML-Code weiter aus. Es gibt insgesamt drei Subroutinen: `HTMLKopf` und `HTMLFuss` setzen mit Hilfe des Operators für Zeichenkettenverknüpfung HTML-Code in einem Skalar zusammen. Am Ende wird dieser Skalar mit der Funktion `return` zurückgegeben.

Etwas komplexer ist die Subroutine `HTMLCode`. Sie erwartet drei Parameter, nämlich einen für das zu erzeugende HTML-Element, einen für dessen Inhalt, und einen für eventuelle CSS-Eigenschaften zur Formatierung des Elements. Abhängig davon (mit if/else wird die entsprechende Weiche gestellt), ob der dritte Parameter einen Inhalt hat, wird der gewünschte HTML-Code zusammengesetzt und das gesamte Konstrukt mit `return` zurückgegeben.

Im Hauptprogramm stehen nur ein paar `print`-Anweisungen. Die Funktion `print` ist so leistungsfähig, dass sie als übergebene Parameter für das, was sie ausgeben soll, auch Aufrufe anderer Funktionen oder eigener Subroutinen erlaubt. Genau davon wird im Beispiel Gebrauch gemacht. Ausgegeben wird dabei der Return-Wert der jeweils aufgerufenen Subroutine. Ebenso könnten Sie den Return-Wert natürlich einer Variablen zuordnen oder etwas anderes damit tun.

### Beachten Sie:

Subroutinen können alle Arten von Variablen zurückgeben, also neben Skalaren auch Listen/Arrays, Hashes und Referenzen. Die aufrufende Anweisung muss dafür sorgen, dass der zurückgegebene Wert im richtigen Variablenformat gespeichert wird. Wenn in einer Subroutine namens `TeileErmitteln` beispielsweise notiert ist:
`return(@Ermittelte);`
dann könnte eine aufrufende Anweisung etwa lauten:
`my @Teile = TeileErmitteln();`
Falls Aufrufspeicher und Rückgabewert nicht vom gleichen Typ sind, greift automatisch die Kontext-Bewertung von Perl. Wenn Sie beispielsweise die gleiche Subroutine aufrufen mit:
`my $Ergebnis = TeileErmitteln();`
Dann ist das, als ob da stünde: `$Ergebnis = @Ermittelte`. Das Ergebnis besteht in dem Fall darin, dass in `$Ergebnis` die Anzahl der zurückgegebenen Array-Elemente steht, weil Perl bei einer Liste im skalaren Kontext die Anzahl der Array-Elemente liefert.

| Tokens
| Reguläre Ausdrücke

© 2007 Impressum