perltie - come nascondere una classe in una semplice variabile
tie VARIABILE, NOME_CLASSE, LISTA
$oggetto = tied VARIABILE
untie VARIABILE
Prima della versione 5.0 di Perl, un programmatore poteva usare dbmopen()
per collegare magicamente un database su disco nel formato Unix standard
dbm(3x) ad un %HASH nel suo programma. Ad ogni modo, Perl era
compilato con una particolare della libreria dbm oppure con un'altra,
ma non con entrambe, e non si poteva estendere questo meccanismo ad
altri package o tipi di variabile.
Adesso si puo`.
La funzione tie() lega una variabile ad una classe (un package) che
fornira` l'implementazione per i metodi di accesso a quella variabile.
Una volta che questa magia si e` realizzata, l'accesso alla variabile
legata fa automaticamente scattare le chiamate ai metodi nella classe
opportuna. La complessita` della classe e` nascosta dietro alle magiche
chiamate ai metodi. I nomi dei metodi sono in LETTERE MAIUSCOLE, che
e` una convenzione usata da Perl per indicare che vengono chiamati
implicitamente anziche` esplicitamente -- proprio come le funzioni
BEGIN() e END().
Nella chiamata a tie(), VARIABILE e` il nome della variabile
su cui lanciare l'incantesimo. CLASSNAME e` il nome della classe
che implementa oggetti del tipo corretto. Qualunque argomento
aggiuntivo nella LISTA viene passato all'appropriato costruttore
per quella classe -- vale a dire TIESCALAR(), TIEARRAY(), TIEHASH()
o TIEHANDLE(). (Tipicamente si tratta di argomenti come quelli
che potrebbero essere passati alla funzione dbminit() del C.)
L'oggetto restituito dal metodo ``new'' viene restituito anche
dalla funzione tie(), cosa che potrebbe risultare utile se voleste
accedere ad altri metodi in NOME_CLASSE . (Non dovete necessariamente
restituire un riferimento al tipo ``giusto'' (ad esempio HASH o
NOME_CLASSE ), basta che sia un oggetto [?]``blessed'' {come tradurre
blessed?}[/?].) Potete inoltre
recuperare un riferimento all'oggetto sottostante usando la
funzione tied().
A differenza di dbmopen(), la funzione tie() non ricorre a use
o require [?]per caricare un modulo {qui mi sono preso molta
liberta`: da rivedere}[/?]-- dovete farlo esplicitamente
per conto vostro.
Una classe che implementa uno scalare legato dovrebbe definire
i seguenti metodi: TIESCALAR, FETCH, STORE, e possibilmente
UNTIE e/o DESTROY.
Esaminiamoli uno ad uno {at each in turn}, usando come esempio una
classe per scalari legati che permette all'utente di fare qualcosa
come:
tie $la_sua_velocita, 'Nice', getppid();
tie $la_mia_velocita, 'Nice', $$;
E ora ogniqualvolta si accede ad una di queste variabili, la sua
priorita` di sistema corrente e` recuperata e restituita. Se
queste variabili vengono impostate, allora la priorita` del
processo viene modificata!
Useremo classe BSD::Resource di Jarkko Hietaniemi <jhi@iki.fi>
per accedere alle costanti PRIO_PROCESS, PRIO_MIN, e PRIO_MAX dal
vostro sistema, e alle chiamate di sistema getpriority() e setpriority().
Ecco il preambolo della classe.
package Nice;
use Carp;
use BSD::Resource;
use strict;
$Nice::DEBUG = 0 unless defined $Nice::DEBUG;
- TIESCALAR nome_classe, LISTA
-
E` il costruttore della classe. Questo significa che e` richiesto
che restituisca un riferimento ``blessed'' al nuovo scalare
(probabilmente anonimo) che sta creando. Per esempio:
sub TIESCALAR {
my $classe = shift;
my $pid = shift || $$; # 0 vuol dire me
if ($pid !~ /^\d+$/) {
carp "Nice::Tie::Scalar ha ricevuto un pid $pid non numerico"
if $^W;
return undef;
}
unless (kill 0, $pid) { # EPERM oERSCH, senza dubbio
carp "Nice::Tie::Scalar ha ricevuto un pid $pid sbagliato: $!"
if $^W;
return undef;
}
return bless \$pid, $classe;
}
Questa classe tie ha scelto di restituire un errore anziche` sollevare
un'eccezione se il suo costruttore dovesse fallire. Benche` questo sia
il modo in cui dbmopen() funziona, altre classi potrebbero non volere
essere cosi` di manica larga. Controlla la variabile globale $^W per
vedere se deve comunque fare un po' di rumore.
- FETCH this
-
Questo metodo viene fatto scattare tutte le volte che si accede (si
legge) alla variabile legata. Non accetta argomenti a parte il riferimento
stesso, che e` l'oggetto che rappresenta lo scalare con cui abbiamo
a che fare. Poiche` in questo caso stiamo usando solo un riferimento a
SCALARE per l'oggetto scalare legato, un semplice $$self permette al
metodo di recuperare il valore ivi memorizzato. Nell'esempio qui
sotto, il valore e` l'ID del processo al quale abbiamo legato la
nostra variabile
sub FETCH {
my $self = shift;
confess "wrong type" unless ref $self;
croak "usage error" if @_;
my $nicety;
local($!) = 0;
$nicety = getpriority(PRIO_PROCESS, $$self);
if ($!) { croak "getpriority failed: $!" }
return $nicety;
}
Questa volta abbiamo deciso di [?]fare i capricci {ho tradotto cosi`
blow up, forse serve qualcosa di piu` forte?}[/?] (sollevare
un'eccezione) se renice fallisce -- altrimenti non c'e` un posto dove
restituire un'eccezione, e probabilmente e` la cosa giusta da fare.
- STORE this, valore
-
Mon Jun 11 22:02:20 2012
|