eval
Nella prima forma, il valore restituito da ESPR viene analizzato
sintatticamente ed eseguito come se fosse un piccolo programma Perl.
Il valore dell'espressione (che viene di per sé determinato
all'interno del contesto scalare) viene prima controllato dal punto
di vista sintattico e, se non ci sono stati errori, eseguito nel
contesto lessicale del programma Perl corrente, in maniera che tutte
le definizioni di formato, le subroutine, e i valori dati alle
variabili rimangano intatti. Va notato che il valore viene verificato
sintatticamente ogni qualvolta l'eval effettua un'esecuzione. Se ESPR
viene omessa, esso valuta $_. Questa forma viene usata tipicamente
per ritardare la verifica sintattica e la successiva esecuzione del
testo di ESPR fino al tempo di esecuzione.
Nella seconda forma, il codice all'interno del BLOCCO viene verificato
sintatticamente solo una volta, allo stesso momento in cui il codice che
circonda lo stesso eval viene verificato sintatticamente, ed eseguito
all'interno del contesto del programma Perl corrente. Questa forma viene
usata tipicamente per catturare le eccezioni in maniera più
efficiente che non la prima (vedete qui sotto), pur fornendo anche il
vantaggio di controllare il codice dentro BLOCCO a tempo di compilazione.
Il punto e virgola finale, se presente, potrebbe essere omesso dal valore
di ESPR o all'interno del BLOCCO.
In entrambe le forme, il valore restituito è il valore dell'ultima
espressione valutata all'interno del mini-programma; può anche
essere usata un'istruzione return, proprio come per le subroutine.
L'espressione che fornisce il valore restituito, viene valutata in un
contesto vuoto, scalare oppure di lista, a seconda del contesto dell'eval
stesso. Si veda wantarray per maggiori informazioni su come può
essere valutata la valutazione del contesto.
Se ci fosse un errore di sintassi o un errore a tempo di esecuzione oppure
se venisse eseguita un'istruzione die, eval restituisce un valore
indefinito e in $@ viene posto il messaggio d'errore.
Se non ci fossero errori, $@ viene garantito essere una stringa nulla.
Fate attenzione al fatto che utilizzare eval non impedisce al perl di
stampare gli avvertimenti su STDERR, né tantomeno il testo degli
avvertimenti viene memorizzato in $@. Per fare entrambe le cose, dovete
usare l'agevolazione data da $SIG{__WARN__} oppure disabilitare gli
avvertimenti all'interno del BLOCCO o ESPR utilizzando
no warnings 'all'. Consultate warn, perlvar, warnings e
perllexwarn.
Va notato che, dato che eval cattura gli errori altrimenti blocanti,
è utile per determinare se una particolare caratteristica (quale
socket o symlink) è implementata. È anche il
meccanismo di cattura delle eccezioni, dove l'operatore die viene usato
per sollevare le eccezioni.
Se il codice che deve essere eseguito non varia, potete usare la forma
eval-BLOCCO per catturare gli errori a tempo di esecuzione senza incorrere
nella penalizzazione di ricompilare ogni volta. L'errore, se c'è,
viene ancora restituito in $@.
Esempi:
# rende la divisione per zero non bloccante
eval { $risposta = $a / $b; }; warn $@ if $@;
# stessa cosa, ma meno efficiente
eval '$risposta = $a / $b'; warn $@ if $@;
# un errore a tempo di compilazione
eval { $risposta = }; # ERRATO
# un errore a tempo di esecuzione
eval '$risposta ='; # imposta $@
Usare la forma eval{} per catturare le eccezioni nelle librerie, presenta
qualche complicanza. A causa del corrente, opinabilmente non corretto, stato degli hook di
__DIE__, potreste non voler innescare alcun hook
per quei __DIE__ che il codice utente potrebbe aver installato. Per
questo scopo si può utilizzare il costrutto local $SIG{__DIE__},
come mostrato in questo esempio:
# una trappola molto privata per l'eccezione divisione-per-zero
eval { local $SIG{'__DIE__'}; $risposta = $a / $b; };
warn $@ if $@;
Questo ha un significato speciale, dato che gli hook di __DIE__
possono chiamare die un'altra volta, e ciò ha l'effetto di
cambiare i loro messaggi d'errore:
# gli hook di __DIE__ pssono modificare i messaggi d'errore
{
local $SIG{'__DIE__'} =
sub { (my $x = $_[0]) =~ s/pippo/pluto/g; die $x };
eval { die "pippo qua e` vivo" };
print $@ if $@; # stampa "pluto qua e` vivo"
}
Visto che questo favorisce le azioni a distanza, questo comportamento
non intuitivo sarà probabilmente risolto in una versione ventura.
Con un eval, dovreste prestare particolare attenzione nel ricordare
cosa si sta esaminando quando:
eval $x; # CASO 1
eval "$x"; # CASO 2
eval '$x'; # CASO 3
eval { $x }; # CASO 4
eval "\$$x++"; # CASO 5
$$x++; # CASO 6
I casi 1 e 2 qua sopra, hanno un comportamento identico: essi eseguono
il codice contenuto nella variabile $x. (Sebbene il caso 2 ha delle
virgolette che sono ingannevoli che fanno sì che il lettore si
chieda cos'altro stia accadendno (nulla)). I casi 3 e 4, similmente,
si comportano allo stesso modo: eseguono il codice in '$x', che non fa
altro che restituire il valore di $x. (Il caso 4 è preferibile
solamente per ragioni visuali, ma ha anche il vantaggio di compilare a
tempo di compilazione invece che a tempo di esecuzione). Il caso 5
è un luogo dove, di norma, vorreste usare le virgolette,
eccetto che in questa particolare situazione, invece potete semplicemente
usare i riferimenti simbolici, proprio come nel caso 6.
eval BLOCCO non viene considerata come un ciclo, dunque le
istruzioni di controllo di un ciclo next, last o redo non
possono essere usate per lasciare o reiniziare il blocco.
Va notato che come caso davvero speciale, un eval '' eseguito all'interno del
package DB non vede l'usuale scope lessicale che lo circonda ma piuttosto lo scope
del primo pezzo di codice che non appartiene al package DB che l'ha chiamato. Di norma,
non si ha bisogno di preoccuparsi di questo a meno che non si stia scrivendo un
debugger del Perl.