Dynamisch creëren en aanroepen van functies is een van de meest flexibele mechanismen in Perl, geërfd uit de tradities van LaTeX en shell-scripts. Sinds de vroege versies staat Perl toe om functies aan te roepen op basis van een string (via symbolische verwijzingen/globs), om verwijzingen naar subprogramma's in variabelen en associatieve arrays op te slaan, en ook de AUTOLOAD-constructie voor het on-the-fly genereren van functies.
Het belangrijkste probleem van deze benadering is veiligheid (de mogelijkheid om een ongewenste functie aan te roepen via een gesimuleerde string) en prestatie (symbolische naamresolutie is langzamer dan directe aanroep). Ook is controle over de scope van functies en het doorgeven van het juiste aantal argumenten belangrijk.
Een oplossing is het gebruik van een hash-dispatcher (mapping van string/sleutel naar coderef), het vermijden van eval voor het uitvoeren van gebruikerscode, en het duidelijk definiëren van de lijst van toegestane te roepen functies.
Voorbeeld van code (dispatch op sleutel):
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); # Geeft 5 } else { die "Onbekende actie $key"; }
Belangrijke kenmerken:
Kan een functie worden aangeroepen op basis van zijn naam, alleen gebruikmakend van een string?
Antwoord: Ja, maar het is gevaarlijk — aanroepen met $fn_name->() of via een directe symbolische verwijzing &$fn_name(); wordt niet aangeraden met externe (gebruikers)gegevens, aangezien dit kan leiden tot potentiële kwetsbaarheden.
Is er een verschil tussen een codeverwijzing en een functienaam in Perl?
Antwoord: Ja, een functienaam is altijd globaal, terwijl een functieverwijzing (coderef) lexicaal, lokaal kan zijn, tussen subprogramma's kan worden doorgegeven en een anonieme functie kan opslaan.
my $coderef = sub { ... }; my $named = \&fn_name;
Wat gebeurt er als een niet-bestaande functie wordt aangeroepen via een hash-dispatcher?
Antwoord: Als de sleutel er niet is — ontstaat er een fout. Daarom is het altijd vereist om exists te controleren voordat u aanroept en om onherkenbare commando's af te handelen, anders zal er geprobeerd worden om undef aan te roepen (fatale fout).
De opdracht op de website accepteert de naam van de functie uit GET-parameters en roept deze aan via eval — elke gebruiker kan system, unlink en andere gevaarlijke functies aanroepen.
Voordelen:
Nadelen:
Een hash met een toegestane lijst van functies wordt gebruikt, alle invoer wordt gevalideerd, eval wordt niet gebruikt, fouten worden opgevangen en gelogd.
Voordelen:
Nadelen: