Utilizzare un filehandle in maniera indiretta significa usare qualcosa di
diverso da un simbolo in un luogo dove è richiesto un filehandle
Di seguito sono riportati alcuni modi per ottenere un filehandle indiretto:
$fh = UN_FH; # parola senza virgolette; E<egrave> ostile a stict subs
$fh = "UN_FH"; # E<egrave> ostile a strict-refs; solo nello stesso package
$fh = *UN_FH; # typeglob
$fh = \*UN_FH; # reference ad un typeglob (bless-abile)
$fh = *UN_FH{IO}; # IO::Handle blessed dal typeglob *UN_FH
Oppure potete servirvi del metodo new da uno dei moduli IO::* per creare
un filehandle anonimo, memorizzarlo in una variabile scalare, ed utilizzarlo
come se fosse un normale filehandle.
use IO::Handle; # 5.004 o superiore
$fh = IO::Handle->new();
Usate poi uno di quelli come fareste con un normale filehandle. Ovunque
Perl si aspetti un filehandle, al suo posto può essere utilizzato
un filehanle indiretto. Un filehandle indiretto è semplicemente
una variabile scalare che contiene un filehandle. Funzioni quali print,
open, seek, o l'operatore <FH> accetteranno sia un filehandle
vero e proprio che una variabile scalare che ne contenga uno:
($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR);
print $ofh "Scrivilo: ";
$ottenuto = <$ifh>;
print $efh "Cos'era quello: $ottenuto";
Se state passando un filehandle ad una funzione, potete scrivere tale
funzione in due modi:
sub accetta_fh {
my $fh = shift;
print $fh "Sto inviando ad un filehandle indiretto\n";
}
Oppure potete localizzare un typeglob ed utilizzare direttamente il filehandle:
sub accetta_fh {
local *FH = shift;
print FH "Sto inviando ad un filehandle localizzato\n";
}
Entrambi gli stili funzionano sia con oggetti che con typeglob che con
filehandle reali. (Potrebbero anche funzionare con stringhe in alcune
circostanze, ma la cosa è rischiosa.)
accept_fh(*STDOUT);
accept_fh($handle);
Negli esempi sopra riportati, abbiamo assegnato il filehandle ad una variabile
scalare prima di utilizzarlo. Ciò accade perché solo le
semplici variabili scalari, e non espressioni o elementi di hash oppure
array, possono essere usati con le funzioni integrate come print e
printf, o con l'operatore diamante [<FH>, NdT]. L'utilizzo di qualcosa
di diverso da una semplice variabile scalare come filehandle non è
consentito, ed il programma non compilerà nemmeno:
@fd = (*STDIN, *STDOUT, *STDERR);
print $fd[1] "Scrivilo: "; # ERRATO
$ottenuto = <$fd[0]>; # ERRATO
print $fd[2] "Cos'era quello: $ottenuto"; # ERRATO
Con print e printf potete aggirare ciò servendovi di un blocco
ed un'espressione al posto del filehandle:
print { $fd[1] } "cose carine\n";
printf { $fd[1] } "Peccato per la povera %x.\n", 3_735_928_559;
# Peccato per la povera deadbeef. [convenzionalmente, uno schema esadecimale utilizzato per riempire parole di memoria, NdT]
Questo blocco è un blocco valido come qualsiasi altro, quindi potete
inserire codice più complesso al suo interno. Il codice di seguito
riportato invia il messaggio in uno dei due posti:
$ok = -x "/bin/cat";
print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n";
print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n";
Questo approccio, consistente nel trattare print e printf come chiamate
a metodi di un oggetto, non funziona con l'operatore diamante. Ciò
accade perché esso è un vero operatore, non solo una funzione
con argomenti non separati da virgola. Ponendo che abbiate memorizzato i
tyeglob nella vostra struttura come indicato in precedenza, potete utilizzare
la funzione integrata readline per leggere un record allo stesso modo
in cui fa <>. Posta l'inizializzazione indicata prima per @fd,
ciò dovrebbe funzionare, ma solo perché readline() richiede
un typeglob. Non funziona con oggetti o stringhe, il che potrebbe essere un
bug che non abbiamo ancora corretto.
$ottenuto = readline($fd[0]);
Va notato che la debolezza dei filehandle indiretti non è collegata
al fatto che essi siano stringhe, typeglob, oggetti, o qualsiasi altra cosa.
è la sintassi degli operatori fondamentali. Il gioco degli oggetti
non vi è di alcun aiuto qui.
|