Die dynamische Erstellung und der Aufruf von Funktionen ist einer der flexibelsten Mechanismen in Perl, der aus den Traditionen von Latex und Shell-Skripten übernommen wurde. Bereits in den frühen Versionen erlaubt Perl den Aufruf von Funktionen durch einen String (über symbolische Links/Globs), das Speichern von Referenzen auf Unterprogramme in Variablen und assoziativen Arrays sowie die AUTOLOAD-Konstruktion zur Generierung von Funktionen zur Laufzeit.
Das Hauptproblem dieses Ansatzes ist die Sicherheit (die Möglichkeit, eine unerwünschte Funktion über einen substituierten String aufzurufen) und die Leistung (symbolische Namensauflösung ist langsamer als der direkte Aufruf). Es ist auch wichtig, die Sichtbarkeit der Funktionen und die Übergabe der korrekten Anzahl von Argumenten zu kontrollieren.
Die Lösung besteht darin, einen Hash-Dispatcher (Mapping von String/Schlüssel zu Coderef) zu verwenden, eval für die Ausführung von Benutzercode zu vermeiden und eine klare Liste zulässiger Funktionsaufrufe zu definieren.
Beispielcode (Dispatcher nach Schlüssel):
my %dispatch = ( add => sub { $_[0] + $_[1] }, sub => sub { $_[0] - $_[1] }, mult => sub { $_[0] * $_[1] }, ); my $key = 'add'; if (exists $dispatch{$key}) { print $dispatch{$key}->(2, 3); # Gibt 5 aus } else { die "Unbekannte Aktion $key"; }
Schlüsselmerkmale:
Kann man eine Funktion nur mit ihrem Namen aus einem String aufrufen?
Antwort: Ja, aber das ist gefährlich — der Aufruf von $fn_name->() oder über einen direkten symbolischen Link &$fn_name(); wird nicht empfohlen mit externen (Benutzerdaten), da dies zu potenziellen Sicherheitsanfälligkeiten führt.
Gibt es einen Unterschied zwischen einer Codereferenz und einem Funktionsnamen in Perl?
Antwort: Ja, der Funktionsname ist immer global, während eine Referenz auf eine Funktion (Coderef) lexikalisch, lokal sein kann, zwischen Unterprogrammen übertragen wird und eine anonyme Funktion speichern kann.
my $coderef = sub { ... }; my $named = \&fn_name;
Was passiert, wenn man eine nicht existierende Funktion über einen Hash-Dispatcher aufruft?
Antwort: Wenn der Schlüssel nicht vorhanden ist, tritt ein Fehler auf. Daher ist es immer erforderlich, exists vor dem Aufruf zu überprüfen und nicht erkannte Befehle zu behandeln, da ansonsten versucht wird, undef aufzurufen (fatale Fehler).
Der Befehl auf der Website nimmt den Funktionsnamen aus dem GET-Parameter und ruft ihn über eval auf — jeder Benutzer kann system, unlink und andere gefährliche Funktionen aufrufen.
Vorteile:
Nachteile:
Es wird ein Hash mit einer Whitelist von Funktionen verwendet, alle Eingaben werden validiert, eval wird nicht verwendet, Fehler werden abgefangen und protokolliert.
Vorteile:
Nachteile: