.\" Automatically generated by Pod::Man 2.06 (Pod::Simple 3.04)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sh \" Subsection heading
.br
.if t .Sp
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. | will give a
.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
.\" expand to `' in nroff, nothing in troff, for use with C<>.
.tr \(*W-|\(bv\*(Tr
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
'br\}
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. nr % 0
. rr F
.\}
.\"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.hy 0
.if n .na
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "PERLTIE 1"
.TH PERLTIE 1 "2006-03-03" "DocFr" "User Contributed Perl Documentation"
.SH "NAME/NOM"
.IX Header "NAME/NOM"
perltie \- Comment cacher un objet d'une classe derrie\*`re une simple variable
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 1
\& tie VARIABLE, CLASSNAME, LIST
\&
\& $object = tied VARIABLE
\&
\& untie VARIABLE
.Ve
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
Avant la version 5.0 de Perl, un programmeur pouvait utiliser la fonction
\&\fIdbmopen()\fR pour connecter magiquement une table de hachage \f(CW%HASH\fR de son
programme a\*` une base de donne\*'es sur disque au format standard Unix \fIdbm\fR\|(3x). En
revanche, son Perl e\*'tait construit avec l'une ou l'autre des imple\*'mentations
de la bibliothe\*`que dbm mais pas les deux et il n'e\*'tait pas possible d'e\*'tendre
ce me\*'canisme a\*` d'autres packages ou a\*` d'autres types de variables.
.PP
C'est maintenant possible.
.PP
La fonction \fItie()\fR relie une variable a\*` une classe (ou un package) qui fournit
l'imple\*'mentation des me\*'thodes permettant d'acce\*'der a\*` cette variable. Une fois
ce lien magique e\*'tablit, l'acce\*`s a\*` cette variable de\*'clenche automatiquement
l'appel aux me\*'thodes de la classe choisie. La complexite\*' de la classe est
cache\*'e derrie\*`re des appels magiques de me\*'thodes. Les noms de ces me\*'thodes sont
entie\*`rement en \s-1MAJUSCULES\s0. C'est une convention pour signifier que Perl peut
appeler ces me\*'thodes implicitement pluto\*^t qu'explicitement \*(-- exactement comme
les fonctions \s-1\fIBEGIN\s0()\fR et \s-1\fIEND\s0()\fR.
.PP
Dans l'appel de \fItie()\fR, \f(CW\*(C`VARIABLE\*(C'\fR est le nom de la variable a\*`
relier. \f(CW\*(C`CLASSNAME\*(C'\fR est le nom de la classe qui imple\*'mente les objets du bon
type. Tous les autres arguments dans \f(CW\*(C`LIST\*(C'\fR sont passe\*'s au constructeur
approprie\*' pour cette classe \*(-- a\*` savoir \s-1\fITIESCALAR\s0()\fR, \s-1\fITIEARRAY\s0()\fR, \s-1\fITIEHASH\s0()\fR, ou
\&\s-1\fITIEHANDLE\s0()\fR. (Ce sont par exemple les arguments a\*` passer a\*` la fonction C
\&\fIdbminit()\fR.) L'objet retourne\*' par la me\*'thode \*(L"new\*(R" est aussi retourne\*' par la
fonction \fItie()\fR ce qui est pratique pour acce\*'der a\*` d'autres me\*'thodes de la
classe \f(CW\*(C`CLASSNAME\*(C'\fR. (Vous n'avez pas besoin de retourner une re\*'fe\*'rence vers
un vrai \*(L"type\*(R" (e.g. \s-1HASH\s0 ou \f(CW\*(C`CLASSNAME\*(C'\fR) tant que c'est un objet
correctement be\*'ni \*(-- par la fonction \fIbless()\fR.) Vous pouvez aussi retrouver une
re\*'fe\*'rence vers l'objet sous-jacent en utilisant la fonction \fItied()\fR.
.PP
A\*` la diffe\*'rence de \fIdbmopen()\fR, la fonction \fItie()\fR ne fera pas pour vous un
\&\f(CW\*(C`use\*(C'\fR ou un \f(CW\*(C`require\*(C'\fR d'un module \*(-- vous devez le faire vous\-me\*^me
explicitement.
.Sh "Les scalaires lie\*'s (par \fItie()\fP)"
.IX Subsection "Les scalaires lie's (par tie())"
Une classe qui imple\*'mente un scalaire lie\*' devrait de\*'finir les me\*'thodes
suivantes\ : \s-1TIESCALAR\s0, \s-1FETCH\s0, \s-1STORE\s0 et e\*'ventuellement \s-1DESTROY\s0.
.PP
Jetons un oeil a\*` chacune d'elle en utilisant comme exemple une classe lie\*'e
(par \fItie()\fR) qui permet a\*` l'utilisateur de faire\ :
.PP
.Vb 2
\& tie $his_speed, 'Nice', getppid();
\& tie $my_speed, 'Nice', $$;
.Ve
.PP
A\*` partir de maintenant, a\*` chaque acce\*`s a\*` l'une de ces variables, la priorite\*'
courante du syste\*`me est retrouve\*'e et retourne\*'e. Si ces variables sont
modifie\*'es alors la priorite\*' du process change.
.PP
Nous utilisons la classe BSD::Resource de Jarkko Hietaniemi <\fIjhi@iki.fi\fR>
(non fournie) pour acce\*'der aux constantes syste\*`mes \s-1PRIO_PROCESS\s0, \s-1PRIO_MIN\s0, et
\&\s-1PRIO_MAX\s0 ainsi qu'aux appels syste\*`mes \fIgetpriority()\fR et \fIsetpriority()\fR. Voici le
pre\*'ambule de la classe\ :
.PP
.Vb 5
\& package Nice;
\& use Carp;
\& use BSD::Resource;
\& use strict;
\& $Nice::DEBUG = 0 unless defined $Nice::DEBUG;
.Ve
.IP "\s-1TIESCALAR\s0 classname, \s-1LIST\s0" 4
.IX Item "TIESCALAR classname, LIST"
C'est le constructeur de la classe. Cela signifie qu'il est suppose\*' retourne\*'
une re\*'fe\*'rence be\*'nie (par \fIbless()\fR) vers un nouveau scalaire (probablement
anonyme) qu'il a cre\*'e\*'. Par exemple\ :
.Sp
.Vb 3
\& sub TIESCALAR {
\& my $class = shift;
\& my $pid = shift || $$; # 0 means me
\&
\& if ($pid !~ /^\ed+$/) {
\& carp "Nice::Tie::Scalar got non\-numeric pid $pid" if $^W;
\& return undef;
\& }
\&
\& unless (kill 0, $pid) { # EPERM or ERSCH, no doubt
\& carp "Nice::Tie::Scalar got bad pid $pid: $!" if $^W;
\& return undef;
\& }
\&
\& return bless \e$pid, $class;
\& }
.Ve
.Sp
Cette classe lie\*'e a choisi de retourner une erreur pluto\*^t que de lancer une
exception si son constructeur e\*'choue. Bien que ce soit la manie\*`re dont
\&\fIdbmopen()\fR fonctionne, d'autres classes peuvent tre\*`s bien e\*^tre moins
tole\*'rantes. La classe regarde tout de me\*^me la variable \f(CW$^W\fR pour savoir si
elle doit e\*'mettre un peu de bruit ou non.
.IP "\s-1FETCH\s0 this" 4
.IX Item "FETCH this"
Cette me\*'thode se de\*'clenche chaque fois qu'on acce\*`de (en lecture) a\*` une
variable lie\*'e. Elle ne prend aucun argument mis a\*` part une re\*'fe\*'rence qui est
l'objet qui repre\*'sente le scalaire a\*` utiliser. Puisque dans notre cas nous
utilisons une simple re\*'fe\*'rence \s-1SCALAIRE\s0 comme objet du scalaire lie\*', un appel
a\*` $$self permet a\*` la me\*'thode d'obtenir la valeur re\*'elle stocke\*'e. Dans notre
exemple ci\-dessous, cette valeur re\*'elle est l'\s-1ID\s0 du process que nous avons lie\*'
a\*` notre variable.
.Sp
.Vb 10
\& 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;
\& }
.Ve
.Sp
Cette fois, nous avons de\*'cide\*' d'exploser (en ge\*'ne\*'rant une exception) si
l'obtention de la priorite\*' e\*'choue \*(-- il n'y a aucun autre moyen pour retourner
une erreur et c'est probablement la meilleure chose a\*` faire.
.IP "\s-1STORE\s0 this, value" 4
.IX Item "STORE this, value"
Cette me\*'thode est appele\*'e a\*` chaque fois que la variable lie\*'e est modifie\*'e
(affecte\*'e). Derrie\*`re sa propre re\*'fe\*'rence, elle attend un (et un seul) argument
\&\*(-- la nouvelle valeur que l'utilisateur essaye d'affecter.
.Sp
.Vb 5
\& sub STORE {
\& my $self = shift;
\& confess "wrong type" unless ref $self;
\& my $new_nicety = shift;
\& croak "usage error" if @_;
\&
\& if ($new_nicety < PRIO_MIN) {
\& carp sprintf
\& "WARNING: priority %d less than minimum system priority %d",
\& $new_nicety, PRIO_MIN if $^W;
\& $new_nicety = PRIO_MIN;
\& }
\&
\& if ($new_nicety > PRIO_MAX) {
\& carp sprintf
\& "WARNING: priority %d greater than maximum system priority %d",
\& $new_nicety, PRIO_MAX if $^W;
\& $new_nicety = PRIO_MAX;
\& }
\&
\& unless (defined setpriority(PRIO_PROCESS, $$self, $new_nicety)) {
\& confess "setpriority failed: $!";
\& }
\& return $new_nicety;
\& }
.Ve
.IP "\s-1DESTROY\s0 this" 4
.IX Item "DESTROY this"
Cette me\*'thode est appele\*'e lorsque la variable lie\*'e doit e\*^tre de\*'truite. Comme
pour les autres classes d'objets, une telle me\*'thode est rarement ne\*'cessaire
parce que Perl de\*'salloue automatiquement pour vous la me\*'moire associe\*' a\*` des
objets moribonds \*(-- ce n'est pas le cas de \*(C+. Nous utilisons donc une
me\*'thode \s-1DESTROY\s0 ici uniquement pour de\*'bugguer.
.Sp
.Vb 5
\& sub DESTROY {
\& my $self = shift;
\& confess "wrong type" unless ref $self;
\& carp "[ Nice::DESTROY pid $$self ]" if $Nice::DEBUG;
\& }
.Ve
.PP
C'est tout ce qu'il y a a\*` voir. C'est me\*^me un peu plus parce que nous avons
fait des jolies petites choses dans un souci de comple\*'tude, robustesse et,
plus ge\*'ne\*'ralement, d'esthe\*'tique. Des classes plus simples liant un scalaire
sont certainement faisables.
.Sh "Les tableaux lie\*'s (par \fItie()\fP)"
.IX Subsection "Les tableaux lie's (par tie())"
Une classe qui imple\*'mente un tableau lie\*' ordinaire devrait de\*'finir les
me\*'thodes suivantes\ : \s-1TIEARRAY\s0, \s-1FETCH\s0, \s-1STORE\s0, \s-1FETCHSIZE\s0, \s-1STORESIZE\s0 et
e\*'ventuellement \s-1DESTROY\s0.
.PP
Les me\*'thodes \s-1FETCHSIZE\s0 et \s-1STORESIZE\s0 sont ne\*'cessaires pour pouvoir fournir
\&\f(CW$#array\fR et autres fonctionnalite\*'s e\*'quivalentes comme \f(CW\*(C`scalar(@array)\*(C'\fR.
.PP
Les me\*'thodes \s-1POP\s0, \s-1PUSH\s0, \s-1SHIFT\s0, \s-1UNSHIFT\s0, \s-1SPLICE\s0, \s-1DELETE\s0 et \s-1EXISTS\s0 sont
indispensables si l'ope\*'rateur Perl ayant le me\*^me nom (mais en minuscules) doit
e\*^tre applique\*' aux tableaux lie\*'s. La classe \fBTie::Array\fR peut e\*^tre utilise\*'e
comme classe de base pour imple\*'menter ces me\*'thodes a\*` partir des cinq me\*'thodes
initiales de base. Les imple\*'mentations par de\*'faut de \s-1DELETE\s0 et de \s-1EXISTS\s0 dans
\&\fBTie::Array\fR appellent simplement \f(CW\*(C`croak\*(C'\fR.
.PP
De plus, la me\*'thode \s-1EXTEND\s0 sera appele\*'e quand perl devra pre\*'\-e\*'tendre
l'allocation du tableau.
.PP
Cela signifie que, maintenant, les tableaux lie\*'s sont complets. L'exemple
ci-dessous doit donc e\*^tre mis a\*` jour pour l'illustrer. (La documentation de
\&\fBTie::Array\fR est plus comple\*`te.)
.PP
Dans cette partie, nous imple\*'menterons un tableau dont les indices sont fixe\*'s
lors sa cre\*'ation. Si vous essayez d'acce\*'der a\*` des indices en dehors des
limites, vous recevrez une exception. Par exemple\ :
.PP
.Vb 9
\& require Bounded_Array;
\& tie @ary, 'Bounded_Array', 2;
\& $| = 1;
\& for $i (0 .. 10) {
\& print "setting index $i: ";
\& $ary[$i] = 10 * $i;
\& $ary[$i] = 10 * $i;
\& print "value of elt $i now $ary[$i]\en";
\& }
.Ve
.PP
Le code en pre\*'ambule de cette classe est le suivant\ :
.PP
.Vb 3
\& package Bounded_Array;
\& use Carp;
\& use strict;
.Ve
.IP "\s-1TIEARRAY\s0 classname, \s-1LIST\s0" 4
.IX Item "TIEARRAY classname, LIST"
C'est le constructeur de la classe. Cela signifie qu'il est suppose\*' retourner
une re\*'fe\*'rence be\*'nie (par \fIbless()\fR) a\*` travers laquelle on pourra acce\*'der au
nouveau tableau (probablement une re\*'fe\*'rence a\*` un \s-1TABLEAU\s0 anonyme)
.Sp
Dans notre exemple, juste pour montrer qu'il n'est pas \fI\s-1VRAIMENT\s0\fR ne\*'cessaire
de retourner une re\*'fe\*'rence vers un \s-1TABLEAU\s0, nous avons choisi une re\*'fe\*'rence a\*`
une \s-1HASHTABLE\s0 pour repre\*'senter notre objet. Cette \s-1HASHTABLE\s0 s'e\*'labore
exactement comme un type d'enregistrement ge\*'ne\*'rique\ : le champ \f(CW\*(C`{BOUND}\*(C'\fR
stockera la borne maximum autorise\*'e et le champ \f(CW\*(C`{ARRAY}\*(C'\fR contiendra la
re\*'fe\*'rence vers le vrai \s-1TABLEAU\s0. Si quelqu'un en dehors de la classe tente de
de\*'re\*'fe\*'rencer l'objet retourne\*' (croyant sans doute avoir a\*` faire a\*` une
re\*'fe\*'rence vers un \s-1TABLEAU\s0), cela ne fonctionnera pas. Tout cela pour vous
montrer que vous devriez respecter le vie prive\*'e des objets.
.Sp
.Vb 10
\& sub TIEARRAY {
\& my $class = shift;
\& my $bound = shift;
\& confess "usage: tie(\e@ary, 'Bounded_Array', max_subscript)"
\& if @_ || $bound =~ /\eD/;
\& return bless {
\& BOUND => $bound,
\& ARRAY => [],
\& }, $class;
\& }
.Ve
.IP "\s-1FETCH\s0 this, index" 4
.IX Item "FETCH this, index"
Cette me\*'thode est appele\*'e a\*` chaque fois qu'on acce\*`de (en lecture) a\*` un e\*'le\*'ment
individuel d'un tableau lie\*'. Elle prend un argument en plus de sa propre
re\*'fe\*'rence\ : l'index de la valeur a\*` laquelle on veut acce\*'der.
.Sp
.Vb 7
\& sub FETCH {
\& my($self,$idx) = @_;
\& if ($idx > $self\->{BOUND}) {
\& confess "Array OOB: $idx > $self\->{BOUND}";
\& }
\& return $self\->{ARRAY}[$idx];
\& }
.Ve
.Sp
Comme vous avez pu le remarquer le nom de la me\*'thode \s-1FETCH\s0 (et al.) est le
me\*^me pour tous les acce\*`s bien que les constructeurs ont des noms diffe\*'rents
(\s-1TIESCALAR\s0 vs \s-1TIEARRAY\s0). En the\*'orie, une me\*^me classe peut servir pour
diffe\*'rents types d'objets lie\*'s. En pratique, cela devient rapidement
encombrant et il est beaucoup plus simple de n'avoir qu'un seul type d'objets
lie\*'s par classe.
.IP "\s-1STORE\s0 this, index, value" 4
.IX Item "STORE this, index, value"
Cette me\*'thode est appele\*'e a\*` chaque fois qu'un e\*'le\*'ment d'un tableau lie\*' est
modifie\*' (affecte\*'). Elle prend deux arguments en plus de sa propre re\*'fe\*'rence\ : l'index de l'e\*'le\*'ment ou\*` nous voulons stocker quelque chose et la valeur que
nous voulons stocker. Par exemple\ :
.Sp
.Vb 8
\& sub STORE {
\& my($self, $idx, $value) = @_;
\& print "[STORE $value at $idx]\en" if _debug;
\& if ($idx > $self\->{BOUND} ) {
\& confess "Array OOB: $idx > $self\->{BOUND}";
\& }
\& return $self\->{ARRAY}[$idx] = $value;
\& }
.Ve
.IP "\s-1DESTROY\s0 this" 4
.IX Item "DESTROY this"
Cette me\*'thode est appele\*'e lorsque qu'une variable lie\*'e doit e\*^tre
de\*'truite. Comme dans le cas des scalaires, cela est rarement ne\*'cessaire avec
un langage qui a son propre ramasse\-miettes. Donc, cette fois nous la
laisserons de co\*^te\*'.
.PP
Le code que nous avons pre\*'sente\*' au de\*'but de la section concernant les tableaux
lie\*'s acce\*`de a\*` de nombreux e\*'le\*'ments du tableau au\-dela\*` de la borne fixe\*'e. Par
la\*` me\*^me, il re\*'cupe\*`re une erreur de\*`s qu'il tente d'acce\*'der au\-dela\*` du second
e\*'le\*'ment comme le montre la sortie suivante\ :
.PP
.Vb 5
\& setting index 0: value of elt 0 now 0
\& setting index 1: value of elt 1 now 10
\& setting index 2: value of elt 2 now 20
\& setting index 3: Array OOB: 3 > 2 at Bounded_Array.pm line 39
\& Bounded_Array::FETCH called at testba line 12
.Ve
.Sh "Les tables de hachage lie\*'es (par \fItie()\fP)"
.IX Subsection "Les tables de hachage lie'es (par tie())"
E\*'tant le premier type de donne\*'es de Perl a\*` e\*^tre lie\*' (voir \fIdbmopen()\fR), les
tables de hachage ont l'imple\*'mentation \fItie()\fR la plus comple\*`te et la plus
pratique. Une classe qui imple\*'mente une table de hachage lie\*'e devrait de\*'finir
les me\*'thodes suivantes : \s-1TIEHASH\s0 est le constructeur ; \s-1FETCH\s0 et \s-1STORE\s0 acce\*`dent
aux paires cle\*'s/valeurs. \s-1EXISTS\s0 indique si une cle\*' est pre\*'sente dans la table
et \s-1DELETE\s0 en supprime une. \s-1CLEAR\s0 vide la table en supprimant toutes les paires
cle\*'/valeur. \s-1FIRSTKEY\s0 et \s-1NEXTKEY\s0 imple\*'mentent les fonctions \fIkeys()\fR et \fIeach()\fR
pour parcourir l'ensemble des cle\*'s. Et \s-1DESTROY\s0 est appele\*'e lorsque la variable
lie\*'e est de\*'truite.
.PP
Si cela vous semble beaucoup, vous pouvez he\*'riter du module standard Tie::Hash
pour la plupart des me\*'thodes et ne rede\*'finir que celles qui vous
inte\*'ressent. Voir Tie::Hash pour plus de de\*'tails.
.PP
Souvenez-vous que Perl distingue le cas ou\*` une cle\*' n'existe pas dans la table
de celui ou\*` la cle\*' existe mais correspond a\*` une valeur \f(CW\*(C`undef\*(C'\fR. Les deux
possibilite\*'s peuvent e\*^tre teste\*'es via les fonctions \f(CW\*(C`exists()\*(C'\fR et
\&\f(CW\*(C`defined()\*(C'\fR.
.PP
Voici l'exemple relativement inte\*'ressant d'une classe liant une table de
hachage\ : cela vous fournit une table de hachage repre\*'sentant tous les
fichiers .* d'un utilisateur. Vous donnez comme index dans la table le nom du
fichier (le point en moins) et vous re\*'cupe\*'rez le contenu de ce fichier. Par
exemple\ :
.PP
.Vb 8
\& use DotFiles;
\& tie %dot, 'DotFiles';
\& if ( $dot{profile} =~ /MANPATH/ ||
\& $dot{login} =~ /MANPATH/ ||
\& $dot{cshrc} =~ /MANPATH/ )
\& {
\& print "you seem to set your MANPATH\en";
\& }
.Ve
.PP
Ou une autre utilisation possible de notre classe lie\*'e\ :
.PP
.Vb 5
\& tie %him, 'DotFiles', 'daemon';
\& foreach $f ( keys %him ) {
\& printf "daemon dot file %s is size %d\en",
\& $f, length $him{$f};
\& }
.Ve
.PP
Dans notre exemple de table de hachage lie\*'e DotFiles, nous utilisons une table
de hachage normale pour stocker dans l'objet plusieurs champs importants dont
le champ \f(CW\*(C`{LIST}\*(C'\fR qui apparai\*^t a\*` l'utilisateur comme le contenu re\*'el de la
table.
.IP "\s-1USER\s0" 5
.IX Item "USER"
l'utilisateur pour lequel l'objet repre\*'sente les fichiers .*
.IP "\s-1HOME\s0" 5
.IX Item "HOME"
l'endroit ou\*` se trouve ces fichiers
.IP "\s-1CLOBBER\s0" 5
.IX Item "CLOBBER"
si nous pouvons essayer de modifier ou de supprimer ces fichiers.
.IP "\s-1LIST\s0" 5
.IX Item "LIST"
la table de hachage des noms des fichiers .* et de leur contenu
.PP
Voici le de\*'but de \fIDotfiles.pm\fR\ :
.PP
.Vb 5
\& package DotFiles;
\& use Carp;
\& sub whowasi { (caller(1))[3] . '()' }
\& my $DEBUG = 0;
\& sub debug { $DEBUG = @_ ? shift : 1 }
.Ve
.PP
Dans notre exemple, nous voulons avoir la possibilite\*' d'e\*'mettre des
informations de debug pour aider au de\*'veloppement. Nous fournissons aussi une
fonction pratique pour aider a\*` l'affichage des messages d'avertissements\ ;
\&\fIwhowasi()\fR retourne le nom de la fonction qui l'a appele\*'.
.PP
Voici les me\*'thodes pour la table de hachage DotFiles.
.IP "\s-1TIEHASH\s0 classname, \s-1LIST\s0" 4
.IX Item "TIEHASH classname, LIST"
C'est le constructeur de la classe. Cela signifie qu'il est suppose\*' retourner
une re\*'fe\*'rence be\*'nie (par \fIbless()\fR) au travers de laquelle on peut acce\*'der au
nouvel objet (probablement mais pas ne\*'cessairement une table de hachage
anonyme).
.Sp
Voici le constructeur\ :
.Sp
.Vb 9
\& sub TIEHASH {
\& my $self = shift;
\& my $user = shift || $>;
\& my $dotdir = shift || '';
\& croak "usage: @{[&whowasi]} [USER [DOTDIR]]" if @_;
\& $user = getpwuid($user) if $user =~ /^\ed+$/;
\& my $dir = (getpwnam($user))[7]
\& || croak "@{[&whowasi]}: no user $user";
\& $dir .= "/$dotdir" if $dotdir;
\&
\& my $node = {
\& USER => $user,
\& HOME => $dir,
\& LIST => {},
\& CLOBBER => 0,
\& };
\&
\& opendir(DIR, $dir)
\& || croak "@{[&whowasi]}: can't opendir $dir: $!";
\& foreach $dot ( grep /^\e./ && \-f "$dir/$_", readdir(DIR)) {
\& $dot =~ s/^\e.//;
\& $node\->{LIST}{$dot} = undef;
\& }
\& closedir DIR;
\& return bless $node, $self;
\& }
.Ve
.Sp
Il n'est pas inutile de pre\*'ciser que, si vous voulez tester un fichier dont le
nom est produit par readdir, vous devez la pre\*'ce\*'der du nom du re\*'pertoire en
question. Sinon, puisque nous ne faisons pas de \fIchdir()\fR ici, il ne testera
sans doute pas le bon fichier.
.IP "\s-1FETCH\s0 this, key" 4
.IX Item "FETCH this, key"
Cette me\*'thode est appele\*'e a\*` chaque fois qu'on acce\*`de (en lecture) a\*` un e\*'le\*'ment
d'une table de hachage lie\*'e. Elle prend un argument en plus de sa propre
re\*'fe\*'rence\ : la cle\*' d'acce\*`s a\*` la valeur que l'on cherche a\*` lire.
.Sp
Voici le code \s-1FETCH\s0 pour notre exemple DotFiles.
.Sp
.Vb 6
\& sub FETCH {
\& carp &whowasi if $DEBUG;
\& my $self = shift;
\& my $dot = shift;
\& my $dir = $self\->{HOME};
\& my $file = "$dir/.$dot";
\&
\& unless (exists $self\->{LIST}\->{$dot} || \-f $file) {
\& carp "@{[&whowasi]}: no $dot file" if $DEBUG;
\& return undef;
\& }
\&
\& if (defined $self\->{LIST}\->{$dot}) {
\& return $self\->{LIST}\->{$dot};
\& } else {
\& return $self\->{LIST}\->{$dot} = `cat $dir/.$dot`;
\& }
\& }
.Ve
.Sp
C'est facile a\*` e\*'crire en lui faisant appeler la commande Unix \fIcat\fR\|(1) mais ce
serait probablement plus portable d'ouvrir le fichier manuellement (et
peut\-e\*^tre plus efficace). Bien su\*^r, puisque les fichiers .* sont un concept
Unix, nous ne sommes pas concerne\*'s.
.IP "\s-1STORE\s0 this, key, value" 4
.IX Item "STORE this, key, value"
Cette me\*'thode est appele\*'e a\*` chaque acce\*`s (en e\*'criture) a\*` un e\*'le\*'ment d'une
table de hachage lie\*'e. Elle prend deux arguments en plus de sa propre
re\*'fe\*'rence\ : la cle\*' qui nous servira pour stocker quelque chose et la valeur
que vous lui associez.
.Sp
Dans notre exemple DotFiles, nous n'autorisons la re\*'e\*'criture du fichier que
dans le cas ou\*` la me\*'thode \fIclobber()\fR a e\*'te\*' appele\*'e a\*` partir de la re\*'fe\*'rence
objet retourne\*'e par \fItie()\fR.
.Sp
.Vb 7
\& sub STORE {
\& carp &whowasi if $DEBUG;
\& my $self = shift;
\& my $dot = shift;
\& my $value = shift;
\& my $file = $self\->{HOME} . "/.$dot";
\& my $user = $self\->{USER};
\&
\& croak "@{[&whowasi]}: $file not clobberable"
\& unless $self\->{CLOBBER};
\&
\& open(F, "> $file") || croak "can't open $file: $!";
\& print F $value;
\& close(F);
\& }
.Ve
.Sp
Si quelqu'un veut e\*'craser quelque chose, il doit dire\ :
.Sp
.Vb 3
\& $ob = tie %daemon_dots, 'daemon';
\& $ob\->clobber(1);
\& $daemon_dots{signature} = "A true daemon\en";
.Ve
.Sp
Un autre moyen de mettre la main sur une re\*'fe\*'rence a\*` l'objet sous-jacent est
d'utiliser la fonction \fItied()\fR. Il serait donc aussi possible de dire\ :
.Sp
.Vb 2
\& tie %daemon_dots, 'daemon';
\& tied(%daemon_dots)\->clobber(1);
.Ve
.Sp
La me\*'thode clobber est tre\*`s simple\ :
.Sp
.Vb 4
\& sub clobber {
\& my $self = shift;
\& $self\->{CLOBBER} = @_ ? shift : 1;
\& }
.Ve
.IP "\s-1DELETE\s0 this, key" 4
.IX Item "DELETE this, key"
Cette me\*'thode est appele\*'e lorsqu'on supprime un e\*'le\*'ment d'une table de hachage
en utilisant par exemple la fonction \fIdelete()\fR. Encore une fois, nous ve\*'rifions
que nous voulons re\*'ellement e\*'craser les fichiers.
.Sp
.Vb 2
\& sub DELETE {
\& carp &whowasi if $DEBUG;
\&
\& my $self = shift;
\& my $dot = shift;
\& my $file = $self\->{HOME} . "/.$dot";
\& croak "@{[&whowasi]}: won't remove file $file"
\& unless $self\->{CLOBBER};
\& delete $self\->{LIST}\->{$dot};
\& my $success = unlink($file);
\& carp "@{[&whowasi]}: can't unlink $file: $!" unless $success;
\& $success;
\& }
.Ve
.Sp
La valeur retourne\*'e par \s-1DELETE\s0 deviendra la valeur retourne\*'e par l'appel a\*`
\&\fIdelete()\fR. Si vous voulez simuler le comportement normal de \fIdelete()\fR, vous
devriez retourner ce qu'aurait retourne\*' \s-1FETCH\s0 pour cette cle\*'. Dans notre
exemple, nous avons pre\*'fe\*'re\*' retourner une valeur qui indique a\*` l'appelant si
le fichier a e\*'te\*' correctement efface\*'.
.IP "\s-1CLEAR\s0 this" 4
.IX Item "CLEAR this"
Cette me\*'thode est appele\*'e lorsque l'ensemble de la table de hachage est
efface\*'e, habituellement en lui affectant la liste vide.
.Sp
Dans notre exemple, cela devrait supprimer tous les fichiers .* de
l'utilisateur ! C'est une chose tellement dangereuse que nous exigeons un
positionnement de \s-1CLOBBER\s0 a\*` une valeur supe\*'rieure a\*` 1 pour l'autoriser.
.Sp
.Vb 10
\& sub CLEAR {
\& carp &whowasi if $DEBUG;
\& my $self = shift;
\& croak "@{[&whowasi]}: won't remove all dot files for $self\->{USER}"
\& unless $self\->{CLOBBER} > 1;
\& my $dot;
\& foreach $dot ( keys %{$self\->{LIST}}) {
\& $self\->DELETE($dot);
\& }
\& }
.Ve
.IP "\s-1EXISTS\s0 this, key" 4
.IX Item "EXISTS this, key"
Cette me\*'thode est appele\*'e lorsque l'utilisateur appelle la fonction \fIexists()\fR
sur une table pour une cle\*' particulie\*`re. Dans notre exemple, nous cherchons
la cle\*' dans la table de hachage \f(CW\*(C`{LIST}\*(C'\fR\ :
.Sp
.Vb 6
\& sub EXISTS {
\& carp &whowasi if $DEBUG;
\& my $self = shift;
\& my $dot = shift;
\& return exists $self\->{LIST}\->{$dot};
\& }
.Ve
.IP "\s-1FIRSTKEY\s0 this" 4
.IX Item "FIRSTKEY this"
Cette me\*'thode est appele\*'e lorsque l'utilisateur commence une ite\*'ration a\*`
travers la table de hachage via un appel a\*` \fIkeys()\fR ou \fIeach()\fR.
.Sp
.Vb 6
\& sub FIRSTKEY {
\& carp &whowasi if $DEBUG;
\& my $self = shift;
\& my $a = keys %{$self\->{LIST}}; # reset each() iterator
\& each %{$self\->{LIST}}
\& }
.Ve
.IP "\s-1NEXTKEY\s0 this, lastkey" 4
.IX Item "NEXTKEY this, lastkey"
Cette me\*'thode est appele\*'e lors d'une ite\*'ration via \fIkeys()\fR ou \fIeach()\fR. Son
second argument est la dernie\*`re cle\*' a\*` laquelle on a acce\*'de\*'. C'est pratique
si vous voulez faire attention a\*` l'ordre, si vous appelez l'ite\*'rateur pour
plusieurs se\*'quences a\*` la fois ou si vous ne stockez pas vos donne\*'es dans une
table de hachage re\*'elle.
.Sp
Dans notre exemple, nous utilisons une vraie table de hachage. Nous pouvons
donc faire simplement en acce\*'dant tout de me\*^me au champ \s-1LIST\s0 de manie\*`re
indirecte.
.Sp
.Vb 5
\& sub NEXTKEY {
\& carp &whowasi if $DEBUG;
\& my $self = shift;
\& return each %{ $self\->{LIST} }
\& }
.Ve
.IP "\s-1DESTROY\s0 this" 4
.IX Item "DESTROY this"
Cette me\*'thode est appele\*'e lorsque une table de hachage lie\*'e va
disparai\*^tre. Vous n'en avez pas re\*'ellement besoin sauf pour de\*'bugguer ou pour
nettoyer quelques donne\*'s auxiliaires. Voici une fonction tre\*`s simple\ :
.Sp
.Vb 3
\& sub DESTROY {
\& carp &whowasi if $DEBUG;
\& }
.Ve
.PP
Notez que des fonctions telles que \fIkeys()\fR et \fIvalues()\fR peuvent retourner des
listes e\*'normes lorsqu'elles sont utilise\*'es sur de gros objets comme des
fichiers \s-1DBM\s0. Vous devriez pluto\*^t utiliser la fonction \fIeach()\fR pour les
parcourir. Exemple\ :
.PP
.Vb 7
\& # print out history file offsets
\& use NDBM_File;
\& tie(%HIST, 'NDBM_File', '/usr/lib/news/history', 1, 0);
\& while (($key,$val) = each %HIST) {
\& print $key, ' = ', unpack('L',$val), "\en";
\& }
\& untie(%HIST);
.Ve
.Sh "Les FileHandle lie\*'s (par \fItie()\fP)"
.IX Subsection "Les FileHandle lie's (par tie())"
Pour l'instant, c'est partiellement imple\*'mente\*'.
.PP
Une classe qui imple\*'mente un filehandle lie\*' devrait de\*'finir les me\*'thode
suivantes\ : \s-1TIEHANDLE\s0, au moins une me\*'thode parmi \s-1PRINT\s0, \s-1PRINTF\s0, \s-1WRITE\s0,
\&\s-1READLINE\s0, \s-1GETC\s0, \s-1READ\s0, et e\*'ventuellement \s-1CLOSE\s0 et \s-1DESTROY\s0. La classe peut aussi
fournir\ : \s-1BINMODE\s0, \s-1OPEN\s0, \s-1EOF\s0, \s-1FILENO\s0, \s-1SEEK\s0 et \s-1TELL\s0 (si les ope\*'rateurs Perl
correspondants sont utilise\*'s sur le descriprteur).
.PP
C'est particulie\*`rement pratique lorsque perl est utilise\*' a\*` l'inte\*'rieur d'un
autre programme dans lequel \s-1STDOUT\s0 et \s-1STDERR\s0 ont e\*'te\*' redirige\*'s d'une manie\*`re
un peu spe\*'ciale. Voir nvi et le module Apache pour des exemples.
.PP
Dans notre exemple, nous essayons de cre\*'er un filehandle crieur (\fIshouting\fR
en anglais).
.PP
.Vb 1
\& package Shout;
.Ve
.IP "\s-1TIEHANDLE\s0 classname, \s-1LIST\s0" 4
.IX Item "TIEHANDLE classname, LIST"
C'est le constructeur de la classe. Cela signifie qu'il est suppose\*' retourner
un re\*'fe\*'rence be\*'nie (par \fIbless()\fR). Cette re\*'fe\*'rence peut e\*^tre utilise\*'e pour
stocker des informations internes.
.Sp
.Vb 1
\& sub TIEHANDLE { print "\en"; my $i; bless \e$i, shift }
.Ve
.IP "\s-1WRITE\s0 this, \s-1LIST\s0" 4
.IX Item "WRITE this, LIST"
Cette me\*'thode est appele\*'e lorsqu'on e\*'crit sur le filehandle via la fonction
\&\f(CW\*(C`syswrite\*(C'\fR.
.Sp
.Vb 5
\& sub WRITE {
\& $r = shift;
\& my($buf,$len,$offset) = @_;
\& print "WRITE called, \e$buf=$buf, \e$len=$len, \e$offset=$offset";
\& }
.Ve
.IP "\s-1PRINT\s0 this, \s-1LIST\s0" 4
.IX Item "PRINT this, LIST"
Cette me\*'thode est appele\*'e lorsqu'on e\*'crit sur le filehandle via la fonction
\&\f(CW\*(C`print()\*(C'\fR. En plus de sa propre re\*'fe\*'rence, elle attend une liste a\*` passer a\*`
la fonction print.
.Sp
.Vb 1
\& sub PRINT { $r = shift; $$r++; print join($,,map(uc($_),@_)),$\e }
.Ve
.IP "\s-1PRINTF\s0 this, \s-1LIST\s0" 4
.IX Item "PRINTF this, LIST"
Cette me\*'thode est appele\*'e lorsqu'on e\*'crit sur le filehandle via la fonction
\&\f(CW\*(C`printf()\*(C'\fR. En plus de sa propre re\*'fe\*'rence, elle attend un format et une
liste a\*` passer a\*` la fonction printf.
.Sp
.Vb 5
\& sub PRINTF {
\& shift;
\& my $fmt = shift;
\& print sprintf($fmt, @_)."\en";
\& }
.Ve
.IP "\s-1READ\s0 this, \s-1LIST\s0" 4
.IX Item "READ this, LIST"
Cette me\*'thode est appele\*'e lorsque le filehandle est lu via les fonctions
\&\f(CW\*(C`read()\*(C'\fR ou \f(CW\*(C`sysread()\*(C'\fR.
.Sp
.Vb 8
\& sub READ {
\& my $self = shift;
\& my $$bufref = \e$_[0];
\& my(undef,$len,$offset) = @_;
\& print "READ called, \e$buf=$bufref, \e$len=$len, \e$offset=$offset";
\& # add to $$bufref, set $len to number of characters read
\& $len;
\& }
.Ve
.IP "\s-1READLINE\s0 this" 4
.IX Item "READLINE this"
Cette me\*'thode est appele\*'e lorsque le filehandle est lu via <\s-1HANDLE\s0>. Elle
devrait retourner undef lorsque il n'y a plus de donne\*'es.
.Sp
.Vb 1
\& sub READLINE { $r = shift; "PRINT called $$r times\en"; }
.Ve
.IP "\s-1GETC\s0 this" 4
.IX Item "GETC this"
Cette me\*'thode est appele\*'e lorsque la fonction \f(CW\*(C`getc\*(C'\fR est appele\*'e.
.Sp
.Vb 1
\& sub GETC { print "Don't GETC, Get Perl"; return "a"; }
.Ve
.IP "\s-1CLOSE\s0 this" 4
.IX Item "CLOSE this"
Cette me\*'thode est appele\*'e lorsque le filehandle est ferme\*' via la fonction
\&\f(CW\*(C`close\*(C'\fR.
.Sp
.Vb 1
\& sub CLOSE { print "CLOSE called.\en" }
.Ve
.IP "\s-1DESTROY\s0 this" 4
.IX Item "DESTROY this"
Comme pour les autres types de variables lie\*'es, cette me\*'thode sera appele\*'e
lorsque le filehandle lie\*' va e\*^tre de\*'truit. C'est pratique pour de\*'bugguer et
e\*'ventuellement nettoyer.
.Sp
.Vb 1
\& sub DESTROY { print "\en" }
.Ve
.PP
Voici comment utiliser notre petit exemple\ :
.PP
.Vb 5
\& tie(*FOO,'Shout');
\& print FOO "hello\en";
\& $a = 4; $b = 6;
\& print FOO $a, " plus ", $b, " equals ", $a + $b, "\en";
\& print ;
.Ve
.ie n .Sh "Pie\*`ge de la fonction ""untie"""
.el .Sh "Pie\*`ge de la fonction \f(CWuntie\fP"
.IX Subsection "Pie`ge de la fonction untie"
Si vous projetez d'utiliser l'objet retourne\*' soit par \fItie()\fR soit par \fItied()\fR et
si la classe lie\*'e de\*'finit un destructeur, il y a un pie\*`ge subtile que vous
\&\fIdevez\fR connai\*^tre.
.PP
Comme base, conside\*'rons cette exemple d'utilisation de tie; la seule chose
qu'il fait est de garder une trace de toutes les valeurs affecte\*'es a\*` un
scalaire.
.PP
.Vb 1
\& package Remember;
\&
\& use strict;
\& use IO::File;
\&
\& sub TIESCALAR {
\& my $class = shift;
\& my $filename = shift;
\& my $handle = new IO::File "> $filename"
\& or die "Cannot open $filename: $!\en";
\&
\& print $handle "The Start\en";
\& bless {FH => $handle, Value => 0}, $class;
\& }
\&
\& sub FETCH {
\& my $self = shift;
\& return $self\->{Value};
\& }
\&
\& sub STORE {
\& my $self = shift;
\& my $value = shift;
\& my $handle = $self\->{FH};
\& print $handle "$value\en";
\& $self\->{Value} = $value;
\& }
\&
\& sub DESTROY {
\& my $self = shift;
\& my $handle = $self\->{FH};
\& print $handle "The End\en";
\& close $handle;
\& }
\&
\& 1;
.Ve
.PP
Voici un exemple d'utilisation\ :
.PP
.Vb 2
\& use strict;
\& use Remember;
\&
\& my $fred;
\& tie $fred, 'Remember', 'myfile.txt';
\& $fred = 1;
\& $fred = 4;
\& $fred = 5;
\& untie $fred;
\& system "cat myfile.txt";
.Ve
.PP
Et voici le re\*'sultat de l'exe\*'cution\ :
.PP
.Vb 5
\& The Start
\& 1
\& 4
\& 5
\& The End
.Ve
.PP
Jusqu'a\*` maintenant, tout va bien. Pour ceux qui ne l'auraient pas remarque\*',
l'objet lie\*' n'a pas encore e\*'te\*' utilise\*'. Ajoutons donc, a\*` la classe Remember,
une me\*'thode supple\*'mentaire permettant de mettre des commentaires dans le
fichier \*(-- disons quelque chose comme\ :
.PP
.Vb 6
\& sub comment {
\& my $self = shift;
\& my $text = shift;
\& my $handle = $self\->{FH};
\& print $handle $text, "\en";
\& }
.Ve
.PP
Voici maintenant l'exemple pre\*'ce\*'dent modifie\*' pour utiliser la me\*'thode
\&\f(CW\*(C`comment\*(C'\fR (qui ne\*'cessite l'objet lie\*')\ :
.PP
.Vb 2
\& use strict;
\& use Remember;
\&
\& my ($fred, $x);
\& $x = tie $fred, 'Remember', 'myfile.txt';
\& $fred = 1;
\& $fred = 4;
\& comment $x "changing...";
\& $fred = 5;
\& untie $fred;
\& system "cat myfile.txt";
.Ve
.PP
Lorsque ce code s'exe\*'cute, il ne produit rien. Voici pourquoi...
.PP
Lorsqu'une variable est lie\*'e, elle est associe\*'e avec l'objet qui est retourne\*'
par la fonction \s-1TIESCALAR\s0, \s-1TIEARRAY\s0, ou \s-1TIEHASH\s0. Cette objet n'a normalement
qu'une seule re\*'fe\*'rence, a\*` savoir, la re\*'fe\*'rence implicite prise par la variable
lie\*'e. Lorsque \fIuntie()\fR est appele\*', cette re\*'fe\*'rence est supprime\*'e, Et donc,
comme dans notre premier exemple ci\-dessus, le destructeur (\s-1DESTROY\s0) de
l'objet est appele\*' ce qui est normal pour un objet qui n'a plus de re\*'fe\*'rence
valide; et donc le fichier est ferme\*'.
.PP
Dans notre second exemple, par contre, nous avons stocke\*' dans \f(CW$x\fR une autre
re\*'fe\*'rence a\*` l'objet lie\*'. Si bien que lorsque \fIuntie()\fR est appele\*', il reste
encore une re\*'fe\*'rence valide sur l'objet, donc le destructeur n'est pas appele\*'
a\*` ce moment et donc le fichier n'est pas ferme\*'. Le buffer du fichier n'e\*'tant
pas vide\*', ceci explique qu'il n'y ait pas de sortie.
.PP
Bon, maintenant que nous connaissons le proble\*`me, que pouvons-nous faire pour
l'e\*'viter\ ? La bonne vieille option \f(CW\*(C`\-w\*(C'\fR vous signalera tout appel a\*`
\&\fIuntie()\fR pour lequel l'objet lie\*' posse\*`de encore des re\*'fe\*'rences valides. Si le
second script ci-dessus est utilise\*' avec l'option \f(CW\*(C`\-w\*(C'\fR, Perl affiche le
message d'avertissement suivant\ :
.PP
.Vb 1
\& untie attempted while 1 inner references still exist
.Ve
.PP
Pour faire fonctionner correctement ce script et sans message, assurez-vous
qu'il n'existe plus de re\*'fe\*'rences valides vers l'objet lie\*' \fIavant\fR d'appeler
\&\fIuntie()\fR\ :
.PP
.Vb 2
\& undef $x;
\& untie $fred;
.Ve
.SH "VOIR AUSSI"
.IX Header "VOIR AUSSI"
Voir DB_File ou Config pour quelques utilisations inte\*'ressantes de
\&\fItie()\fR.
.SH "BUGS"
.IX Header "BUGS"
Les tableaux lie\*'s sont \fIincomplets\fR. Il y a quelques lacunes comme l'acce\*`s a\*`
\&\f(CW$#TABLEAU\fR (qui est difficile puisque c'est une lvalue) mais aussi les
autres fonctions de manipulation des tableaux telles que \fIpush()\fR, \fIpop()\fR,
\&\fIshift()\fR, \fIunshift()\fR et \fIsplice()\fR.
.PP
Vous ne pouvez pas lier facilement une structure multi-niveaux (comme une
table de tables de hachage) a\*` un fichier dbm. Le premier proble\*`me est la
limite de taille d'une valeur (sauf pour \s-1GDBM\s0 et Berkeley \s-1DB\s0). Mais, au\-dela\*`,
vous aurez aussi le proble\*`me du stockage de re\*'fe\*'rences sur disque. L'un des
modules qui tentent de re\*'pondre a\*` ce genre de besoins est encore expe\*'rimental
et partiel\ : le module \s-1MLDBM\s0. Cherchez le code source de \s-1MLDBM\s0 sur le site
\&\s-1CPAN\s0 le plus proche (comme de\*'crit dans perlmodlib).
.SH "AUTEURS"
.IX Header "AUTEURS"
Tom Christiansen
.PP
\&\s-1TIEHANDLE\s0 par Sven Verdoolaege <\fIskimo@dns.ufsia.ac.be\fR> et Doug MacEachern
<\fIdougm@osf.org\fR>
.SH "TRADUCTION"
.IX Header "TRADUCTION"
.Sh "Version"
.IX Subsection "Version"
Cette traduction franc\*,aise correspond a\*` la version anglaise distribue\*'e avec
perl 5.6.0. Pour en savoir plus concernant ces traductions, consultez
.
.Sh "Traducteur"
.IX Subsection "Traducteur"
Traduction initiale et mise a\*` jour v5.6.0\ : Paul Gaborit
.Sh "Relecture"
.IX Subsection "Relecture"
Re\*'gis Julie\*'