Il s'agit de la commande perltie qui peut être exécutée dans le fournisseur d'hébergement gratuit OnWorks en utilisant l'un de nos multiples postes de travail en ligne gratuits tels que Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS.
PROGRAMME:
Nom
perltie - comment masquer une classe d'objet dans une variable simple
SYNOPSIS
cravate VARIABLE, NOM DE CLASSE, LISTE
$objet = VARIABLE liée
dénouer VARIABLE
DESCRIPTION
Avant la version 5.0 de Perl, un programmeur pouvait utiliser dbmopen() pour connecter un disque
base de données sous Unix standard dBM(3x) formatez comme par magie en %HASH dans leur programme.
Cependant, leur Perl a été construit avec une bibliothèque dbm particulière ou une autre, mais pas
les deux, et vous ne pouvez pas étendre ce mécanisme à d’autres packages ou types de variables.
Maintenant vous pouvez.
Le attacher() La fonction lie une variable à une classe (package) qui fournira le
implémentation des méthodes d'accès pour cette variable. Une fois cette magie réalisée,
l'accès à une variable liée déclenche automatiquement des appels de méthode dans la classe appropriée. Le
la complexité de la classe est cachée derrière les appels de méthodes magiques. Les noms des méthodes sont dans TOUS
CAPS, qui est une convention utilisée par Perl pour indiquer qu'ils sont appelés implicitement
plutôt qu'explicitement - tout comme le COMMENCER() et FIN() fonctions.
Dans l' attacher() appel, "VARIABLE" est le nom de la variable à enchanter. "NOM DE CLASSE" est
le nom d'une classe implémentant des objets du type correct. Tout argument supplémentaire dans
la "LISTE" est transmise à la méthode constructeur appropriée pour cette classe, ce qui signifie
TIESCALAR(), TIEARRAY(), TIEHASH(), ou POIGNÉE D'ATTAQUE(). (Ce sont généralement des arguments tels que
comme cela pourrait être transmis au dbminit() fonction de C.) L'objet renvoyé par le "nouveau"
La méthode est également renvoyée par le attacher() fonction, qui serait utile si vous vouliez
accéder à d'autres méthodes dans "CLASSNAME". (Vous n'êtes pas réellement obligé de renvoyer une référence à un
bon "type" (par exemple, HASH ou "CLASSNAME") tant qu'il s'agit d'un objet correctement béni.) Vous
peut également récupérer une référence à l'objet sous-jacent à l'aide du lié() la fonction.
Contrairement à dbmopen(), la attacher() la fonction n'"utilisera" ni ne "nécessitera" un module pour vous - vous
devez le faire explicitement vous-même.
Attacher Scalaires
Une classe implémentant un scalaire lié doit définir les méthodes suivantes : TIESCALAR, FETCH,
STOCKER, et éventuellement DÉTACHER et/ou DÉTRUIRE.
Examinons-les tour à tour, en utilisant comme exemple une classe tie pour les scalaires qui permet
l'utilisateur doit faire quelque chose comme :
tie $his_speed, 'Nice', getppid();
attachez $my_speed, 'Nice', $$ ;
Et maintenant, chaque fois que l'on accède à l'une de ces variables, sa priorité système actuelle est
récupéré et restitué. Si ces variables sont définies, alors la priorité du processus est
changé!
Nous utiliserons Jarkko Hietaniemi[email protected]>'s BSD::Resource class (non inclus) pour y accéder
les constantes PRIO_PROCESS, PRIO_MIN et PRIO_MAX de votre système, ainsi que les
obtenir la priorité() et définir la priorité() appels système. Voici le préambule du cours.
forfait Nice;
utiliser la carpe ;
utiliser BSD::Ressource;
utiliser strict;
$Nice::DEBUG = 0 sauf si défini $Nice::DEBUG;
nom de classe TIESCALAR, LIST
C'est le constructeur de la classe. Cela signifie qu'on s'attend à ce qu'il revienne
référence à un nouveau scalaire (probablement anonyme) qu'il crée. Par exemple:
sous TIESCALAR {
ma $classe = shift;
mon $pid = shift || $$ ; #0 signifie moi
si ($pid !~ /^\d+$/) {
carp "Nice::Tie::Scalar a obtenu un pid non numérique $pid" si $^W ;
retourner undef ;
}
else (kill 0, $pid) { # EPERM ou ERSCH, sans aucun doute
carpe "Nice::Tie::Scalar a un mauvais pid $pid: $!" si $^W ;
retourner undef ;
}
return bénisse \$pid, $class;
}
Cette classe tie a choisi de renvoyer une erreur plutôt que de lever une exception si son
le constructeur devrait échouer. Alors que c'est comme ça dbmopen() fonctionne, d'autres classes pourraient bien
je ne souhaite pas être aussi indulgent. Il vérifie la variable globale $^W pour voir s'il faut émettre
un peu de bruit quand même.
RÉCUPÉRER ceci
Cette méthode sera déclenchée à chaque accès (lecture) à la variable liée. Il
ne prend aucun argument au-delà de son auto-référence, qui est l'objet représentant le
scalaire auquel nous avons affaire. Parce que dans ce cas, nous utilisons simplement une référence SCALAIRE pour le
objet scalaire lié, un simple $$self permet à la méthode d'obtenir la valeur réelle stockée
là. Dans notre exemple ci-dessous, cette valeur réelle est l'ID de processus auquel nous avons lié
notre variable.
sous FETCH {
mon $self = shift;
avouer « mauvais type » à moins que ref $self ;
croak "erreur d'utilisation" si @_;
ma $gentilité ;
local($!) = 0;
$nicety = getpriority(PRIO_PROCESS, $$self);
if ($!) { croak "getpriority a échoué : $!" }
retourner $nicety ;
}
Cette fois, nous avons décidé de faire exploser (de lever une exception) si la renice échoue --il y a
autrement, nous n'avons aucun endroit pour renvoyer une erreur, et c'est probablement la bonne chose à faire.
STOCKEZ ceci, valeur
Cette méthode sera déclenchée chaque fois que la variable liée est définie (attribuée). Au-delà
son auto-référence, il attend également un (et un seul) argument : la nouvelle valeur du
l'utilisateur essaie d'attribuer. Ne vous inquiétez pas de renvoyer une valeur depuis STORE ; la sémantique
d'affectation renvoyant la valeur assignée est implémentée avec FETCH.
sous-MAGASIN {
mon $self = shift;
avouer « mauvais type » à moins que ref $self ;
mon $new_nicety = shift ;
croak "erreur d'utilisation" si @_;
si ($new_nicety < PRIO_MIN) {
sprint de carpe
"AVERTISSEMENT : priorité %d inférieure à la priorité système minimale %d",
$new_nicety, PRIO_MIN si $^W ;
$new_nicety = PRIO_MIN ;
}
si ($new_nicety > PRIO_MAX) {
sprint de carpe
"AVERTISSEMENT : priorité %d supérieure à la priorité système maximale %d",
$new_nicety, PRIO_MAX si $^W ;
$new_nicety = PRIO_MAX ;
}
à moins que (défini setpriority(PRIO_PROCESS, $$self, $new_nicety)) {
confesser « échec de la définition : $ ! » ;
}
}
DÉLIER ce
Cette méthode sera déclenchée lorsque le « dénouement » se produira. Cela peut être utile si la classe
a besoin de savoir quand aucun autre appel ne sera effectué. (Sauf DESTROY bien sûr.) Voir "Le
"dénouez" Gotcha "ci-dessous pour plus de détails.
DÉTRUISEZ ceci
Cette méthode sera déclenchée lorsque la variable liée devra être détruite. Comme avec
d'autres classes d'objets, une telle méthode est rarement nécessaire, car Perl libère son
la mémoire de l'objet moribond pour vous automatiquement - ce n'est pas du C++, vous savez. Nous utiliserons un
Méthode DESTROY ici à des fins de débogage uniquement.
sous-DÉTRUIRE {
mon $self = shift;
avouer « mauvais type » à moins que ref $self ;
carpe "[ Nice::DESTROY pid $$self ]" if $Nice::DEBUG;
}
C'est à peu près tout ce qu'il y a à faire. En fait, c'est plus que tout ce qu'il y a à faire, parce que
nous avons fait quelques belles choses ici par souci d'exhaustivité, de robustesse et de généralité
esthétique. Des cours TIESCALAR plus simples sont certainement possibles.
Attacher Arrays
Une classe implémentant un tableau ordinaire lié doit définir les méthodes suivantes : TIEARRAY,
FETCH, STORE, FETCHSIZE, STORESIZE, CLEAR et peut-être UNTIE et/ou DESTROY.
FETCHSIZE et STORESIZE sont utilisés pour fournir $#array et son équivalent "scalar (@array)"
accéder.
Les méthodes POP, PUSH, SHIFT, UNSHIFT, SPLICE, DELETE et EXISTS sont requises si le perl
L'opérateur avec le nom correspondant (mais en minuscules) doit opérer sur le tableau lié. Le
Cravate :: Tableau La classe peut être utilisée comme classe de base pour implémenter les cinq premiers d'entre eux en termes
des méthodes de base ci-dessus. Les implémentations par défaut de DELETE et EXISTS dans
Cravate :: Tableau simplement "croasser".
De plus, EXTEND sera appelé lorsque Perl aura une allocation pré-étendue dans un environnement réel.
Tableau.
Pour cette discussion, nous allons implémenter un tableau dont les éléments ont une taille fixe lors de la création.
Si vous essayez de créer un élément plus grand que la taille fixe, vous ferez une exception. Pour
Exemple:
utilisezFixedElem_Array ;
attachez @array, 'FixedElem_Array', 3;
$array[0] = 'chat'; # d'accord.
$array[1] = 'chiens'; # exception, longueur('chiens') > 3.
Le code du préambule de la classe est le suivant :
paquetFixedElem_Array ;
utiliser la carpe ;
utiliser strict;
nom de classe TIEARRAY, LIST
C'est le constructeur de la classe. Cela signifie qu'on s'attend à ce qu'il revienne
référence à travers laquelle le nouveau tableau (probablement une référence ARRAY anonyme) sera
accédé.
Dans notre exemple, juste pour vous montrer que ce n'est pas le cas vraiment je dois retourner un ARRAY
référence, nous choisirons une référence HASH pour représenter notre objet. Un HASH fonctionne
ainsi qu'un type d'enregistrement générique : le champ "{ELEMSIZE}" stockera le maximum d'éléments
taille autorisée, et le champ "{ARRAY}" contiendra la véritable référence ARRAY. Si quelqu'un
en dehors de la classe essaie de déréférencer l'objet renvoyé (en pensant sans doute que c'est un
ARRAY réf), ils vont exploser. Cela montre simplement que vous devez respecter un
la vie privée de l'objet.
sous TIEARRAY {
ma $classe = shift;
mon $elemsize = shift ;
si ( @_ || $elemsize =~ /\D/ ) {
croak "utilisation : tie ARRAY, '" . __EMBALLER__ . "', taille_elem";
}
reviens bénisse {
ELEMSIZE => $elemsize,
TABLEAU => [],
}, $classe ;
}
RÉCUPÉRER ceci, indexer
Cette méthode sera déclenchée chaque fois qu'un élément individuel du tableau lié est
consulté (lu). Il prend un argument au-delà de son auto-référence : l'index dont
valeur que nous essayons d'obtenir.
sous FETCH {
mon $self = shift;
mon $index = décalage ;
return $self->{ARRAY}->[$index];
}
Si un index de tableau négatif est utilisé pour lire un tableau, l'index sera traduit
à un positif en interne en appelant FETCHSIZE avant d'être transmis à FETCH. Toi
peut désactiver cette fonctionnalité en attribuant une vraie valeur à la variable $NEGATIVE_INDICES
dans la classe des tableaux liés.
Comme vous l'avez peut-être remarqué, le nom de la méthode FETCH (et al.) est le même pour tous
accès, même si les constructeurs diffèrent par leurs noms (TIESCALAR vs TIEARRAY). Alors que
en théorie, vous pourriez avoir la même classe desservant plusieurs types liés, en pratique cela
devient fastidieux, et il est plus facile de les limiter à un seul type d'égalité par classe.
STOCKER ceci, index, valeur
Cette méthode sera déclenchée chaque fois qu'un élément du tableau lié est défini
(écrit). Il prend deux arguments au-delà de son auto-référence : l'index auquel nous nous trouvons
essayer de stocker quelque chose et la valeur que nous essayons d'y mettre.
Dans notre exemple, "undef" est en réalité "$self->{ELEMSIZE}" nombre d'espaces donc nous avons un
un peu plus de travail à faire ici :
sous-MAGASIN {
mon $self = shift;
mon( $index, $value ) = @_;
if ( longueur $value > $self->{ELEMSIZE} ) {
croak "la longueur de $value est supérieure à $self->{ELEMSIZE}" ;
}
# Remplir les espaces vides
$self->EXTEND( $index ) si $index > $self->FETCHSIZE();
# justifier à droite pour conserver la taille des éléments pour les éléments plus petits
$self->{ARRAY}->[$index] = sprintf "%$self->{ELEMSIZE}s", $value;
}
Les index négatifs sont traités de la même manière qu'avec FETCH.
FETCHIZE ce
Renvoie le nombre total d'éléments dans le tableau lié associé à l'objet ceci..
(Équivalent à « scalaire (@array) »). Par exemple:
sous FETCHSIZE {
mon $self = shift;
return scalaire @{$self->{ARRAY}} ;
}
STORESIZE ceci, comptez
Définit le nombre total d'éléments dans le tableau lié associé à l'objet ceci. être
compter. Si cela agrandit le tableau, le mappage de "undef" par la classe devrait être
revenu pour de nouveaux postes. Si le tableau devient plus petit, les entrées dépassent le nombre
devrait être supprimé.
Dans notre exemple, 'undef' est en réalité un élément contenant "$self->{ELEMSIZE}" le nombre de
les espaces. Observer:
sous TAILLE DU MAGASIN {
mon $self = shift;
mon $count = shift ;
if ( $count > $self->FETCHSIZE() ) {
foreach ( $count - $self->FETCHSIZE() .. $count ) {
$self->STORE( $_, '' );
}
} elsif ( $count < $self->FETCHSIZE() ) {
foreach ( 0 .. $self->FETCHSIZE() - $count - 2 ) {
$self->POP();
}
}
}
PROLONGER cela, compter
Appel informatif que le tableau est susceptible de croître pour avoir compter entrées. Peut être utilisé pour
optimiser l'allocation. Cette méthode ne nécessite rien.
Dans notre exemple, nous voulons nous assurer qu'il n'y a pas d'entrées vides ("undef"), donc "EXTEND"
utilisera "STORESIZE" pour remplir les éléments selon les besoins :
sous ÉTENDRE {
mon $self = shift;
mon $count = shift ;
$self->STORESIZE( $count );
}
EXISTE ceci, clé
Vérifiez que l'élément à l'index clé existe dans le tableau lié ceci..
Dans notre exemple, nous déterminerons que si un élément est constitué de "$self->{ELEMSIZE}"
espaces uniquement, il n'existe pas :
sous EXISTE {
mon $self = shift;
mon $index = décalage ;
renvoie 0 si ! défini $self->{ARRAY}->[$index] ||
$self->{ARRAY}->[$index] eq ' ' x $self->{ELEMSIZE};
1 revenir;
}
SUPPRIMER ceci, touche
Supprimer l'élément à l'index clé du tableau lié ceci..
Dans notre exemple, un élément supprimé est constitué d'espaces "$self->{ELEMSIZE}" :
sous SUPPRIMER {
mon $self = shift;
mon $index = décalage ;
return $self->STORE( $index, '' );
}
EFFACER ceci
Effacer (supprimer, supprimer, ...) toutes les valeurs du tableau lié associé à l'objet
ceci.. Par exemple:
sous CLEAR {
mon $self = shift;
return $self->{ARRAY} = [];
}
POUSSER ceci, LISTE
Ajouter des éléments de LISTE au tableau. Par exemple:
sous PUSH {
mon $self = shift;
ma @liste = @_;
mon $last = $self->FETCHSIZE();
$self->STORE( $last + $_, $list[$_] ) foreach 0 .. $#list;
return $self->FETCHSIZE();
}
POP ceci
Supprimez le dernier élément du tableau et renvoyez-le. Par exemple:
sous-POP {
mon $self = shift;
return pop @{$self->{ARRAY}} ;
}
MAJ ce
Supprimez le premier élément du tableau (en décalant les autres éléments vers le bas) et renvoyez-le.
Par exemple :
sous MAJ {
mon $self = shift;
return shift @{$self->{ARRAY}} ;
}
DÉSHIFT ceci, LIST
Insérez des éléments LIST au début du tableau, en déplaçant les éléments existants jusqu'à
faire de la place. Par exemple:
sous UNSHIFT {
mon $self = shift;
ma @liste = @_;
mon $size = scalaire( @list );
# faites de la place pour notre liste
@{$self->{ARRAY}}[ $size .. $#{$self->{ARRAY}} + $size ]
= @{$self->{ARRAY}} ;
$self->STORE( $_, $list[$_] ) foreach 0 .. $#list;
}
SPLICE this, décalage, longueur, LISTE
Effectuez l'équivalent de "splice" sur la baie.
compenser est facultatif et la valeur par défaut est zéro, les valeurs négatives sont décomptées à partir de la fin de
le tableau.
longueur est facultatif et correspond par défaut au reste du tableau.
LISTE peut être vide.
Renvoie une liste de l'original longueur éléments à compenser.
Dans notre exemple, nous utiliserons un petit raccourci s'il y a un LISTE:
sous-ÉPISSURE {
mon $self = shift;
mon $offset = décalage || 0 ;
ma longueur $ = décalage || $self->FETCHSIZE() - $offset ;
ma @list = ();
si ( @_ ) {
attachez @list, __PACKAGE__, $self->{ELEMSIZE} ;
@liste = @_;
}
return splice @{$self->{ARRAY}}, $offset, $length, @list;
}
DÉLIER ce
Sera appelé lorsque "untie" se produira. (Voir "Le "dénouement" Gotcha" ci-dessous.)
DÉTRUISEZ ceci
Cette méthode sera déclenchée lorsque la variable liée devra être détruite. Comme avec
la classe tie scalaire, cela n'est presque jamais nécessaire dans un langage qui fait le sien
la collecte des ordures, donc cette fois nous allons simplement la laisser de côté.
Attacher Des hachis
Les hachages ont été le premier type de données Perl à être lié (voir dbmopen()). Une classe implémentant un
Le hachage lié doit définir les méthodes suivantes : TIEHASH est le constructeur. RÉCUPÉRER et
STORE accéder aux paires clé et valeur. EXISTS indique si une clé est présente dans le
hachage, et DELETE en supprime un. CLEAR vide le hachage en supprimant toutes les clés et valeurs
paires. FIRSTKEY et NEXTKEY implémentent le clés() et chaque() fonctions pour parcourir tout
les clés. SCALAR est déclenché lorsque le hachage lié est évalué dans un contexte scalaire. DÉLÂCHER est
appelé lorsque "untie" se produit, et DESTROY est appelé lorsque la variable liée est une poubelle
collectées.
Si cela vous semble beaucoup, n'hésitez pas à hériter simplement du Tie::StdHash standard.
module pour la plupart de vos méthodes, en redéfinissant uniquement les plus intéressantes. Voir Tie::Hash pour
détails.
N'oubliez pas que Perl fait la distinction entre une clé n'existant pas dans le hachage et la clé
existant dans le hachage mais ayant une valeur correspondante de "undef". Les deux possibilités
peut être testé avec les fonctions "exists()" et "defined()".
Voici un exemple de classe de hachage liée quelque peu intéressante : elle vous donne un hachage
représentant les fichiers de points d'un utilisateur particulier. Vous indexez le hachage avec le nom du
fichier (moins le point) et vous récupérez le contenu de ce fichier de points. Par exemple:
utilisez DotFiles ;
lien %dot, 'DotFiles' ;
si ( $point{profil} =~ /MANPATH/ ||
$dot{connexion} =~ /MANPATH/ ||
$point{cshrc} =~ /MANPATH/ )
{
print "vous semblez définir votre MANPATH\n" ;
}
Ou voici un autre exemple d'utilisation de notre classe liée :
attachez %lui, 'DotFiles', 'démon';
foreach $f ( clés %lui ) {
printf "Le fichier de points du démon %s a une taille %d\n",
$f, longueur $lui{$f} ;
}
Dans notre exemple DotFiles de hachage lié, nous utilisons un hachage régulier pour l'objet contenant plusieurs
champs importants, dont seul le champ "{LIST}" sera ce que l'utilisateur considère comme le
du vrai hasch.
UTILISATEUR dont les fichiers points représentent cet objet
HOME où vivent ces fichiers de points
TABASSER
si nous devrions essayer de modifier ou de supprimer ces fichiers de points
LISTE le hachage des noms de fichiers de points et les mappages de contenu
Voici le début de Dotfiles.pm:
paquet DotFiles ;
utiliser la carpe ;
sous whowasi { (votre interlocuteur(1))(3] . '()' }
mon $DEBUG = 0 ;
sous débogage { $DEBUG = @_ ? décalage : 1 }
Pour notre exemple, nous voulons pouvoir émettre des informations de débogage pour faciliter le traçage pendant
développement. Nous conservons également une fonction pratique en interne pour faciliter l'impression.
avertissements; whowasi() renvoie le nom de la fonction qui l'appelle.
Voici les méthodes pour le hachage lié DotFiles.
Nom de classe TIEHASH, LISTE
C'est le constructeur de la classe. Cela signifie qu'on s'attend à ce qu'il revienne
référence par laquelle le nouvel objet (probablement mais pas nécessairement un objet anonyme)
hachage) sera accessible.
Voici le constructeur :
sous TIEHASH {
mon $self = shift;
mon $user = shift || $> ;
mon $dotdir = shift || '';
croak "utilisation : @{[&whowasi]} [USER [DOTDIR]]" si @_;
$user = getpwuid($user) si $user =~ /^\d+$/;
mon $dir = (getpwnam($user))[7]
|| croak "@{[&whowasi]} : aucun utilisateur $user" ;
$dir .= "/$dotdir" si $dotdir;
mon $nœud = {
UTILISATEUR => $utilisateur,
ACCUEIL => $rép,
LISTE => {},
CLOBBER => 0,
};
ouvrir le répertoire (DIR, $dir)
|| croak "@{[&whowasi]} : impossible d'ouvrir le répertoire $dir : $!" ;
foreach $dot ( grep /^\./ && -f "$dir/$_", readdir(DIR)) {
$point =~ s/^\.//;
$node->{LIST}{$dot} = undef ;
}
fermé DIR ;
return bless $node, $self;
}
Cela vaut probablement la peine de mentionner que si vous souhaitez tester les valeurs de retour
d'un readdir, vous feriez mieux d'ajouter le répertoire en question. Sinon, parce que nous
n'a pas chdir() là, il aurait testé le mauvais fichier.
RÉCUPÉREZ ceci, clé
Cette méthode sera déclenchée à chaque accès à un élément du hachage lié.
(lire). Il prend un argument au-delà de sa propre référence : la clé dont nous considérons la valeur.
essayant d'aller chercher.
Voici la récupération de notre exemple DotFiles.
sous FETCH {
carpe &whowasi si $DEBUG;
mon $self = shift;
mon $dot = shift ;
mon $dir = $self->{HOME} ;
mon $fichier = "$dir/.$dot" ;
sauf si (existe $self->{LIST}->{$dot} || -f $file) {
carp "@{[&whowasi]} : pas de fichier $dot" si $DEBUG ;
retourner undef ;
}
if (défini $self->{LIST}->{$dot}) {
return $self->{LIST}->{$dot} ;
} Else {
return $self->{LIST}->{$dot} = `cat $dir/.$dot` ;
}
}
C'était facile à écrire en l'appelant Unix cat(1) commande, mais ce serait probablement
être plus portable pour ouvrir le fichier manuellement (et un peu plus efficace). Bien sûr,
parce que les fichiers de points sont un concept Unixy, nous ne sommes pas très concernés.
STOCKEZ ceci, clé, valeur
Cette méthode sera déclenchée chaque fois qu'un élément du hachage lié est défini (écrit).
Il prend deux arguments au-delà de son auto-référence : l'index auquel nous essayons de
stocker quelque chose et la valeur que nous essayons d'y mettre.
Ici, dans notre exemple DotFiles, nous ferons attention à ne pas les laisser essayer d'écraser le
fichier à moins qu'ils n'aient appelé le tabasser() méthode sur la référence d'objet d'origine
retourné par attacher().
sous-MAGASIN {
carpe &whowasi si $DEBUG;
mon $self = shift;
mon $dot = shift ;
ma valeur $ = décalage ;
mon $file = $self->{HOME} . "/.$point";
mon $user = $self->{USER} ;
croak "@{[&whowasi]} : $fichier non modifiable"
sauf si $self->{CLOBBER} ;
ouvrir(mon $f, '>', $file) || croak "impossible d'ouvrir $file: $!";
imprimer $f $valeur ;
fermer($f);
}
S’ils voulaient écraser quelque chose, ils pourraient dire :
$ob = tie %daemon_dots, 'démon';
$ob->tabasser(1);
$daemon_dots{signature} = "Un vrai démon\n";
Une autre façon de mettre la main sur une référence à l'objet sous-jacent est d'utiliser le lié()
fonction, ils auraient donc pu définir alternativement Clobber en utilisant :
tie %daemon_dots, 'démon';
lié(%daemon_dots)->tabasser(1);
La méthode du clobber est simplement :
sous-cobber {
mon $self = shift;
$self->{CLOBBER} = @_ ? décalage : 1 ;
}
SUPPRIMER ceci, touche
Cette méthode est déclenchée lorsque nous supprimons un élément du hachage, généralement en utilisant
le delete () fonction. Encore une fois, nous veillerons à vérifier s'ils souhaitent réellement
écraser les fichiers.
sous SUPPRIMER {
carpe &whowasi si $DEBUG;
mon $self = shift;
mon $dot = shift ;
mon $file = $self->{HOME} . "/.$point";
croak "@{[&whowasi]} : ne supprimera pas le fichier $file"
sauf si $self->{CLOBBER} ;
supprimer $self->{LIST}->{$dot} ;
mon $success = unlink($file);
carp "@{[&whowasi]} : impossible de dissocier $file : $!" à moins que $succès ;
$succès ;
}
La valeur renvoyée par DELETE devient la valeur de retour de l'appel à delete (). Si vous
vouloir imiter le comportement normal de delete (), vous devriez retourner n'importe quel FETCH
serait revenu pour cette clé. Dans cet exemple, nous avons plutôt choisi de renvoyer un
valeur qui indique à l'appelant si le fichier a été supprimé avec succès.
EFFACER ceci
Cette méthode est déclenchée lorsque tout le hachage doit être effacé, généralement en attribuant
la liste vide.
Dans notre exemple, cela supprimerait tous les fichiers de points de l'utilisateur ! C'est tellement dangereux
chose qu'ils devront régler CLOBBER sur quelque chose de supérieur à 1 pour que cela se produise.
sous CLEAR {
carpe &whowasi si $DEBUG;
mon $self = shift;
croak "@{[&whowasi]} : ne supprimera pas tous les fichiers de points pour $self->{USER}"
sauf si $self->{CLOBBER} > 1 ;
mon point $ ;
foreach $dot ( clés %{$self->{LIST}}) {
$self->DELETE($dot);
}
}
EXISTE ceci, clé
Cette méthode est déclenchée lorsque l'utilisateur utilise le existe() fonction sur un particulier
hacher. Dans notre exemple, nous examinerons l'élément de hachage "{LIST}" pour ceci :
sous EXISTE {
carpe &whowasi si $DEBUG;
mon $self = shift;
mon $dot = shift ;
return existe $self->{LIST}->{$dot} ;
}
FIRSTKEY ce
Cette méthode sera déclenchée lorsque l'utilisateur va parcourir le hachage, tel que
comme via un clés(), valeurs (), ou chaque() appel.
sous PREMIÈRE CLÉ {
carpe &whowasi si $DEBUG;
mon $self = shift;
mon $a = clés %{$self->{LIST}} ; # réinitialiser chaque itérateur()
chaque %{$self->{LIST}}
}
FIRSTKEY est toujours appelé dans un contexte scalaire et doit simplement renvoyer la première clé.
valeurs ()et chaque() dans un contexte de liste, appellera FETCH pour les clés renvoyées.
NEXTKEY ceci, lastkey
Cette méthode est déclenchée lors d'un clés(), valeurs (), ou chaque() itération. Il a un
deuxième argument qui est la dernière clé à laquelle on a accédé. Ceci est utile si
vous souhaitez commander ou appeler l'itérateur à partir de plusieurs séquences, ou
pas vraiment stocker les choses dans un hachage n'importe où.
NEXTKEY est toujours appelé dans un contexte scalaire et doit simplement renvoyer la clé suivante.
valeurs ()et chaque() dans un contexte de liste, appellera FETCH pour les clés renvoyées.
Pour notre exemple, nous utilisons un vrai hachage, nous allons donc faire la chose simple, mais nous allons
il faut passer par le champ LISTE indirectement.
sous NEXTKEY {
carpe &whowasi si $DEBUG;
mon $self = shift;
renvoie chaque %{ $self->{LIST} }
}
SCALAIRE ce
Ceci est appelé lorsque le hachage est évalué dans un contexte scalaire. Afin d'imiter le
comportement des hachages déliés, cette méthode doit renvoyer une fausse valeur lorsque le hachage lié
est considéré comme vide. Si cette méthode n'existe pas, Perl fera quelques recherches
devine et renvoie vrai lorsque le hachage est à l'intérieur d'une itération. Si ce n'est pas le cas,
FIRSTKEY est appelé, et le résultat sera une valeur fausse si FIRSTKEY renvoie le vide
liste, vrai sinon.
Cependant, vous devriez pas comptez aveuglément sur Perl pour qu'il fasse toujours ce qu'il faut.
En particulier, Perl renverra true par erreur lorsque vous effacerez le hachage à plusieurs reprises
appeler DELETE jusqu'à ce qu'il soit vide. Il vous est donc conseillé de fournir votre propre SCALAIRE
méthode lorsque vous voulez être absolument sûr que votre hachage se comporte bien en scalaire
contexte
Dans notre exemple, nous pouvons simplement appeler « scalaire » le hachage sous-jacent référencé par
"$self->{LISTE}" :
sous SCALAIRE {
carpe &whowasi si $DEBUG;
mon $self = shift;
return scalaire %{ $self->{LIST} }
}
DÉLIER ce
C'est ce qu'on appelle lorsque le « dénouement » se produit. Voir « Le « dénouement » Gotcha » ci-dessous.
DÉTRUISEZ ceci
Cette méthode est déclenchée lorsqu'un hachage lié est sur le point de sortir du champ d'application. Tu ne le fais pas
j'en ai vraiment besoin, sauf si vous essayez d'ajouter un débogage ou d'avoir un état auxiliaire à nettoyer
en haut. Voici une fonction très simple :
sous-DÉTRUIRE {
carpe &whowasi si $DEBUG;
}
Notez que des fonctions telles que clés() et valeurs () peut renvoyer d'énormes listes lorsqu'il est utilisé sur de grandes
objets, comme les fichiers DBM. Vous préférerez peut-être utiliser le chaque() fonction pour itérer sur ceux-ci.
Exemple :
# imprimer les décalages du fichier historique
utiliser NDBM_File ;
tie(%HIST, 'NDBM_File', '/usr/lib/news/history', 1, 0);
while (($key,$val) = chaque %HIST) {
print $key, ' = ', unpack('L',$val), "\n" ;
}
délier(%HIST);
Attacher Poignées de fichiers
Ceci est partiellement mis en œuvre maintenant.
Une classe implémentant un descripteur de fichier lié doit définir les méthodes suivantes : TIEHANDLE, à
au moins un parmi PRINT, PRINTF, WRITE, READLINE, GETC, READ et éventuellement CLOSE, UNTIE et
DÉTRUIRE. La classe peut également fournir : BINMODE, OPEN, EOF, FILENO, SEEK, TELL - si le
Les opérateurs Perl correspondants sont utilisés sur le handle.
Lorsque STDERR est lié, sa méthode PRINT sera appelée pour émettre des avertissements et des messages d'erreur.
Cette fonctionnalité est temporairement désactivée pendant l'appel, ce qui signifie que vous pouvez utiliser "warn()"
à l’intérieur de PRINT sans démarrer une boucle récursive. Et tout comme "__WARN__" et "__DIE__"
gestionnaires, la méthode PRINT de STDERR peut être appelée pour signaler les erreurs de l'analyseur, donc les mises en garde
mentionné sous "%SIG" dans perlvar apply.
Tout cela est particulièrement utile lorsque Perl est intégré à un autre programme, où la sortie
vers STDOUT et STDERR peuvent devoir être redirigés d'une manière spéciale. Voir nvi et le
Module Apache pour des exemples.
Lorsque vous attachez une poignée, le premier argument de "tie" doit commencer par un astérisque. Donc si
vous attachez STDOUT, utilisez *STDOUT. Si vous l'avez assigné à une variable scalaire, disons
$handle, utilisez *$handle. "tie $handle" lie la variable scalaire $handle, pas le handle
à l'intérieur.
Dans notre exemple, nous allons créer une poignée de crier.
paquet Crier ;
nom de classe TIEHANDLE, LIST
C'est le constructeur de la classe. Cela signifie qu'on s'attend à ce qu'il revienne
référence en quelque sorte. La référence peut être utilisée pour contenir certaines informations internes.
sous TIEHANDLE { imprimer " \n"; mon $i; bénis \$i, shift }
ÉCRIVEZ ceci, LISTE
Cette méthode sera appelée lorsque le handle sera écrit via la fonction "syswrite".
sous ÉCRIRE {
$r = décalage ;
ma($buf,$len,$offset) = @_;
print "WRITE appelé, \$buf=$buf, \$len=$len, \$offset=$offset";
}
IMPRIMER ceci, LISTE
Cette méthode sera déclenchée chaque fois que la poignée liée est imprimée avec le
Fonctions "print()" ou "say()". Au-delà de son autoréférence, il attend également la liste
qui a été transmis à la fonction d'impression.
sous PRINT { $r = décalage ; $$r++ ; print join($,,map(uc($_),@_)),$\ }
"say()" agit comme "print()" sauf que $\ sera localisé en "\n", vous devez donc le faire
rien de spécial pour gérer "say()" dans "PRINT()".
IMPRIMER ceci, LISTE
Cette méthode sera déclenchée chaque fois que la poignée liée est imprimée avec le
fonction "printf()". Au-delà de son auto-référence, il attend également le format et la liste
qui a été passé à la fonction printf.
sous PRINTF {
décalage;
mon $fmt = décalage ;
print sprintf($fmt, @_);
}
LIRE ceci, LISTE
Cette méthode sera appelée lorsque le handle sera lu via le "read" ou "sysread"
fonctions.
sous LIRE {
mon $self = shift;
mon $bufref = \$_[0];
mon(undef,$len,$offset) = @_;
print "READ appelé, \$buf=$bufref, \$len=$len, \$offset=$offset";
# ajouter à $$bufref, définir $len sur le nombre de caractères lus
$len;
}
LIRE ceci
Cette méthode est appelée lorsque le handle est lu via " " ou " readline HANDLE ".
Conformément à "readline", dans un contexte scalaire, il doit renvoyer la ligne suivante, ou "undef" pour non
plus de données. Dans un contexte de liste, il doit renvoyer toutes les lignes restantes ou une liste vide pour
plus de données. Les chaînes renvoyées doivent inclure le séparateur d'enregistrement d'entrée $/ (voir
perlvar), sauf s'il s'agit de "undef" (ce qui signifie mode "slurp").
sous READLINE {
mon $r = décalage ;
si (wantarray) {
return ("tous les restants\n",
"s'aligne\n",
"à eof\n");
} Else {
renvoie "READLINE appelé" . ++$$r . " fois\n";
}
}
GETC ce
Cette méthode sera appelée lorsque la fonction "getc" sera appelée.
sub GETC { print "Ne pas GETC, Get Perl"; renvoie "a" ; }
EOF ce
Cette méthode sera appelée lorsque la fonction "eof" sera appelée.
À partir de Perl 5.12, un paramètre entier supplémentaire sera transmis. Ce sera
zéro si "eof" est appelé sans paramètre ; 1 si "eof" reçoit un descripteur de fichier comme
paramètre, par exemple "eof(FH)" ; et 2 dans le cas très particulier où le descripteur de fichier lié est
"ARGV" et "eof" sont appelés avec une liste de paramètres vide, par exemple "eof()".
sub EOF { pas de longueur $stringbuf }
FERMER ce
Cette méthode sera appelée à la fermeture du handle via la fonction "close".
sub CLOSE { print "CLOSE appelé.\n" }
DÉLIER ce
Comme pour les autres types de liens, cette méthode sera appelée lorsque le « dénouement » se produira. Il
peut être approprié de « FERMER automatiquement » lorsque cela se produit. Voir « Le « dénouement » Gotcha » ci-dessous.
DÉTRUISEZ ceci
Comme pour les autres types de liens, cette méthode sera appelée lorsque la poignée liée est
sur le point d'être détruit. Ceci est utile pour le débogage et éventuellement le nettoyage.
sous DESTROY { imprimer " \n" }
Voici comment utiliser notre petit exemple :
cravate(*FOO,'Crier');
imprimer FOO "bonjour\n" ;
$une = 4 ; $b = 6 ;
print FOO $a, " plus ", $b, " égal ", $a + $b, "\n";
imprimer ;
DÉLIER ceci.
Vous pouvez définir pour tous les types de liens une méthode UNTIE qui sera appelée à délier(). Voir le
"dénouez" Gotcha "ci-dessous.
Le "délier" Gotcha
Si vous avez l'intention d'utiliser l'objet renvoyé par l'un ou l'autre attacher() or lié()et si le
la classe cible de tie définit un destructeur, il y a un piège subtil pour vous doit se prémunir contre.
En guise de configuration, considérons cet exemple (certes plutôt artificiel) d’égalité ; tout ce qu'il fait c'est utiliser
un fichier pour conserver un journal des valeurs attribuées à un scalaire.
forfait N'oubliez pas ;
utiliser strict;
utiliser des avertissements ;
utiliser IO::Fichier ;
sous TIESCALAR {
ma $classe = shift;
mon $filename = shift ;
mon $handle = IO::File->new( "> $filename" )
ou die "Impossible d'ouvrir $filename : $!\n" ;
print $handle "Le Début\n" ;
bénisse {FH => $handle, Value => 0}, $class;
}
sous FETCH {
mon $self = shift;
retourner $self->{Valeur} ;
}
sous-MAGASIN {
mon $self = shift;
ma valeur $ = décalage ;
mon $handle = $self->{FH} ;
print $handle "$valeur\n" ;
$self->{Valeur} = $valeur ;
}
sous-DÉTRUIRE {
mon $self = shift;
mon $handle = $self->{FH} ;
print $handle "La Fin\n" ;
fermer $handle ;
}
1;
Voici un exemple qui utilise cette cravate :
utiliser strict;
utilisez Se souvenir ;
mon $fred;
tie $fred, 'Remember', 'myfile.txt';
$fred = 1 ;
$fred = 4 ;
$fred = 5 ;
détachez $fred;
système "cat monfichier.txt" ;
Voici le résultat lors de son exécution :
Le début
1
4
5
La Fin
Jusqu'ici, tout va bien. Ceux d'entre vous qui ont prêté attention auront remarqué que le
l'objet lié n'a pas été utilisé jusqu'à présent. Ajoutons donc une méthode supplémentaire à la classe Remember pour
permettre l'inclusion de commentaires dans le fichier ; dis, quelque chose comme ça :
sous-commentaire {
mon $self = shift;
mon $text = shift ;
mon $handle = $self->{FH} ;
print $handle $text, "\n";
}
Et voici l'exemple précédent modifié pour utiliser la méthode "comment" (qui nécessite le
objet lié) :
utiliser strict;
utilisez Se souvenir ;
mon ($fred, $x);
$x = tie $fred, 'Remember', 'myfile.txt';
$fred = 1 ;
$fred = 4 ;
commentaire $x "changeant..." ;
$fred = 5 ;
détachez $fred;
système "cat monfichier.txt" ;
Lorsque ce code est exécuté, il n'y a aucune sortie. Voici pourquoi:
Lorsqu'une variable est liée, elle est associée à l'objet qui est la valeur de retour du
Fonction TIESCALAR, TIEARRAY ou TIEHASH. Cet objet n'a normalement qu'une seule référence,
à savoir, la référence implicite de la variable liée. Quand délier() s'appelle, que
la référence est détruite. Ensuite, comme dans le premier exemple ci-dessus, le destructeur de l'objet
(DESTROY) est appelé, ce qui est normal pour les objets qui n'ont plus de références valides ; et
le dossier est donc clos.
Cependant, dans le deuxième exemple, nous avons stocké une autre référence à l'objet lié dans $x.
Cela veut dire que quand délier() est appelé, il y aura toujours une référence valide au
objet existant, donc le destructeur n'est pas appelé à ce moment-là, et donc le fichier est
pas fermé. La raison pour laquelle il n'y a pas de sortie est que les tampons de fichiers n'ont pas été
vidé sur le disque.
Maintenant que vous savez quel est le problème, que pouvez-vous faire pour l’éviter ? Avant le
introduction de la méthode facultative UNTIE, le seul moyen était le bon vieux drapeau "-w". Lequel
détectera tous les cas où vous appelez délier() et il existe encore des références valables au
objet lié. Si le deuxième script au-dessus près du haut "utilisez les avertissements" dénouer "" ou a été
exécuté avec l'indicateur "-w", Perl affiche ce message d'avertissement :
tentative de dénouement alors que 1 références internes existent encore
Pour que le script fonctionne correctement et fasse taire l'avertissement, assurez-vous qu'il n'y a pas de code valide
références à l'objet lié avant délier() est appelé:
undef $x;
détachez $fred;
Maintenant qu'UNTIE existe, le concepteur de classe peut décider quelles parties de la fonctionnalité de classe
sont en réalité associés au "délier" et à l'objet en cours de destruction. Ce qui rend
le sens d'une classe donnée dépend du fait que les références internes soient conservées de manière à ce que
des méthodes non liées aux liens peuvent être appelées sur l'objet. Mais dans la plupart des cas, cela fait probablement
Il est logique de déplacer la fonctionnalité qui aurait été dans DESTROY vers la méthode UNTIE.
Si la méthode UNTIE existe, l'avertissement ci-dessus ne se produit pas. Au lieu de cela, la méthode UNTIE
reçoit le nombre de références "supplémentaires" et peut émettre son propre avertissement le cas échéant.
Par exemple, pour reproduire le cas non UNTIE, cette méthode peut être utilisée :
sous UNTIE
{
mon ($obj,$count) = @_;
carp "dénouement tenté alors que les références internes $count existent encore" if $count;
}
Utilisez Perltie en ligne en utilisant les services onworks.net
