La creazione e l'invocazione dinamica di funzioni è uno dei meccanismi più flessibili di Perl, ereditato dalle tradizioni di latex e script di shell. Fin dalle prime versioni, Perl permette di invocare funzioni tramite stringhe (attraverso riferimenti simbolici/globs), memorizzare riferimenti a sottoprogrammi in variabili e array associativi, e utilizzare la costruzione AUTOLOAD per generare funzioni al volo.
Il principale problema di questo approccio è la sicurezza (la possibilità di invocare una funzione indesiderata tramite una stringa falsa) e le prestazioni (la risoluzione simbolica dei nomi è più lenta rispetto a una chiamata diretta). È inoltre importante avere il controllo sull'ambito delle funzioni e sulla trasmissione del numero corretto di argomenti.
La soluzione è utilizzare un dispatcher hash (mapping da stringa/parola chiave a coderef), evitare l'uso di eval per eseguire codice utente, e definire chiaramente l'elenco delle funzioni autorizzate per l'invocazione.
Esempio di codice (dispatch in base alla chiave):
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); # Stampa 5 } else { die "Unknown action $key"; }
Caratteristiche chiave:
Si può invocare una funzione per nome, utilizzando solo una stringa?
Risposta: Sì, ma è pericoloso — chiamare $fn_name->() o tramite un riferimento simbolico diretto &$fn_name(); non è consigliato con dati esterni (utenti), poiché questo porta a potenziali vulnerabilità.
C'è differenza tra un riferimento a codice e il nome di una funzione in Perl?
Risposta: Sì, il nome di una funzione è sempre globale, mentre un riferimento a funzione (coderef) può essere lessicale, locale, passando tra sottoprogrammi e contenere una funzione anonima.
my $coderef = sub { ... }; my $named = \&fn_name;
Cosa succede se si invoca una funzione inesistente tramite hash dispatcher?
Risposta: Se la chiave non esiste — si verifica un errore. Quindi è sempre necessaria una verifica exists prima dell'invocazione e la gestione di comandi non riconosciuti, altrimenti si tenterà di invocare undef (errore fatale).
Una richiesta sul sito riceve il nome di una funzione da un parametro GET e chiama tramite eval — qualsiasi utente può invocare system, unlink e altre funzioni pericolose.
Pro:
Contro:
Viene utilizzato un hash con un elenco bianco di funzioni, tutte le metriche vengono validate, l'eval non viene utilizzato, e gli errori vengono intercettati e registrati.
Pro:
Contro: