.\" 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\*'