.\" 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 "PERLBOOT 1" .TH PERLBOOT 1 "2006-03-03" "DocFr" "User Contributed Perl Documentation" .SH "NAME/NOM" .IX Header "NAME/NOM" perlboot \- Tutoriel pour l'oriente\*' objet a\*` destination des de\*'butants .SH "DESCRIPTION" .IX Header "DESCRIPTION" Si vous n'e\*^tes pas familier avec les notions de programmation oriente\*'e objet d'autres langages, certaines documentations concernant les objets en Perl doivent vous sembler de\*'courageantes. Ces documents sont perlobj, la re\*'fe\*'rence sur l'utilisation des objets, et perltoot qui pre\*'sente, sous forme de tutoriel, les particularite\*'s des objets en Perl. .PP Ici nous utiliserons une approche diffe\*'rente en supposant que vous n'avez aucune expe\*'rience pre\*'alable avec l'objet. Il est quand me\*^me souhaitable de connai\*^tre les subroutines (perlsub), les re\*'fe\*'rences (perlref et autres) et les paquetages (perlmod). Essayez de vous familiariser avec ces concepts si vous ne l'avez pas de\*'ja\*` fait. .Sh "Si nous pouvions parler aux animaux..." .IX Subsection "Si nous pouvions parler aux animaux..." Supposons un instant que les animaux parlent\ : .PP .Vb 9 \& sub Boeuf::fait { \& print "un Boeuf fait mheuu !\en"; \& } \& sub Cheval::fait { \& print "un Cheval fait hiiii !\en"; \& } \& sub Mouton::fait { \& print "un Mouton fait be\*^e\*^e\*^ !\en" \& } \& \& Boeuf::fait; \& Cheval::fait; \& Mouton::fait; .Ve .PP Le re\*'sultat sera : .PP .Vb 3 \& un Boeuf fait mheuu ! \& un Cheval fait hiiii ! \& un Mouton fait be\*^e\*^e\*^ ! .Ve .PP Ici, rien de spectaculaire. De simples subroutines, bien que dans des paquetages se\*'pare\*'s, appele\*'es en utilisant leur nom complet (incluant le nom du paquetage). Cre\*'ons maintenant un troupeau\ : .PP .Vb 5 \& # Boeuf::fait, Cheval::fait, Mouton::fait comme au\-dessus \& @troupeau = qw(Boeuf Boeuf Cheval Mouton Mouton); \& foreach $animal (@troupeau) { \& &{$animal."::fait"}; \& } .Ve .PP Le re\*'sultat sera\ : .PP .Vb 5 \& un Boeuf fait mheuu ! \& un Boeuf fait mheuu ! \& un Cheval fait hiiii ! \& un Mouton fait be\*^e\*^e\*^ ! \& un Mouton fait be\*^e\*^e\*^ ! .Ve .PP Super. Mais l'utilisation de re\*'fe\*'rences symboliques vers les subroutines \&\f(CW\*(C`fait\*(C'\fR est un peu de\*'plaisante. Nous comptons sur le mode \f(CW\*(C`no strict subs\*(C'\fR ce qui n'est certainement pas recommande\*' pour de gros programmes. Et pourquoi est-ce ne\*'cessaire\ ? Parce que le nom du paquetage semble inse\*'parable du nom de la subroutine que nous voulons appeler dans ce paquetage. .PP L'est\-ce vraiment\ ? .Sh "Pre\*'sentation de l'appel de me\*'thodes via l'ope\*'rateur fle\*`che" .IX Subsection "Pre'sentation de l'appel de me'thodes via l'ope'rateur fle`che" Pour l'instant, disons que \f(CW\*(C`Class\->method\*(C'\fR appelle la subroutine \&\f(CW\*(C`method\*(C'\fR du paquetage \f(CW\*(C`Class\*(C'\fR. (Ici, X\ Class\ X est utilise\*' dans le sens X\ cate\*'gorie\ X et non dans son sens X\ universitaire\ X.) Ce n'est pas tout a\*` fait vrai mais allons-y pas a\*` pas. Nous allons maintenant utiliser cela\ : .PP .Vb 4 \& # Boeuf::fait, Cheval::fait, Mouton::fait comme au\-dessus \& Boeuf\->fait; \& Cheval\->fait; \& Mouton\->fait; .Ve .PP A\*` nouveau, le re\*'sultat sera\ : .PP .Vb 3 \& un Boeuf fait mheuu ! \& un Cheval fait hiiii ! \& un Mouton fait be\*^e\*^e\*^ ! .Ve .PP Ce n'est pas encore super\ : me\*^me nombre de caracte\*`res, que des constantes, pas de variables. Mais maintenant, on peut se\*'parer les choses\ : .PP .Vb 2 \& $a = "Boeuf"; \& $a\->fait; # appelle Boeuf\->fait .Ve .PP Ah\ ! Maintenant que le nom du paquetage est se\*'pare\*' du nom de la subroutine, on peut utiliser un nom de paquetage variable. Et cette fois, nous avons quelque chose qui marche me\*^me lorsque \f(CW\*(C`use strict refs\*(C'\fR est actif. .Sh "Et pour tout un troupeau" .IX Subsection "Et pour tout un troupeau" Prenons ce nouvel appel via l'ope\*'rateur fle\*`che et appliquons-le dans l'exemple du troupeau\ : .PP .Vb 9 \& sub Boeuf::fait { \& print "un Boeuf fait mheuu !\en"; \& } \& sub Cheval::fait { \& print "un Cheval fait hiiii !\en"; \& } \& sub Mouton::fait { \& print "un Mouton fait be\*^e\*^e\*^ !\en" \& } \& \& @troupeau = qw(Boeuf Boeuf Cheval Mouton Mouton); \& foreach $animal (@troupeau) { \& $animal\->fait; \& } .Ve .PP C\*,a y est\ ! Maintenant tous les animaux parlent et sans utiliser de re\*'fe\*'rence symbolique. .PP Mais regardez tout ce code commun. Toutes les routines \f(CW\*(C`fait\*(C'\fR ont une structure similaire\ : un ope\*'rateur \f(CW\*(C`print\*(C'\fR et une chai\*^ne qui contient un texte identique, excepte\*'s deux mots. Ce serait inte\*'ressant de pouvoir factoriser les parties communes au cas ou\*` nous de\*'ciderions plus tard de changer \f(CW\*(C`fait\*(C'\fR en \f(CW\*(C`dit\*(C'\fR par exemple. .PP Il y a re\*'ellement moyen de le faire mais pour cela nous devons tout d'abord en savoir un peu plus sur ce que l'ope\*'rateur fle\*`che peut faire pour nous. .Sh "Le parame\*`tre implicite de l'appel de me\*'thodes" .IX Subsection "Le parame`tre implicite de l'appel de me'thodes" L'appel\ : .PP .Vb 1 \& Class\->method(@args) .Ve .PP essaie d'appeler la subroutine \f(CW\*(C`Class::method\*(C'\fR de la manie\*`re suivante\ : .PP .Vb 1 \& Class::method("Class", @args); .Ve .PP (Si la subroutine ne peut e\*^tre trouve\*'e, l'he\*'ritage intervient mais nous le verrons plus tard.) Cela signifie que nous re\*'cupe\*'rons le nom de la classe comme premier parame\*`tre (le seul parame\*`tre si aucun autre argument n'est fourni). Donc nous pouvons re\*'e\*'crire la subroutine \f(CW\*(C`fait\*(C'\fR du \f(CW\*(C`Mouton\*(C'\fR ainsi\ : .PP .Vb 4 \& sub Mouton::fait { \& my $class = shift; \& print "un $class fait be\*^e\*^e\*^ !\en"; \& } .Ve .PP Et, de manie\*`re similaire, pour les deux autres animaux\ : .PP .Vb 8 \& sub Boeuf::fait { \& my $class = shift; \& print "un $class fait mheuu !\en"; \& } \& sub Cheval::fait { \& my $class = shift; \& print "un $class fait hiiii !\en"; \& } .Ve .PP Dans chaque cas, \f(CW$class\fR aura la valeur approprie\*'e pour la subroutine. Mais, encore une fois, nous avons des structures similaires. Pouvons-nous factoriser encore plus\ ? Oui, en appelant une autre me\*'thode de la me\*^me classe. .Sh "Appel a\*` une seconde me\*'thode pour simplifier les choses" .IX Subsection "Appel a` une seconde me'thode pour simplifier les choses" Cre\*'ons donc une seconde me\*'thode nomme\*'e \f(CW\*(C`cri\*(C'\fR qui sera appele\*'e depuis \&\f(CW\*(C`fait\*(C'\fR. Cette me\*'thode fournit un texte constant repre\*'sentant le cri lui\-me\*^me. .PP .Vb 7 \& { package Boeuf; \& sub cri { "mheuu" } \& sub fait { \& my $class = shift; \& print "un $class fait ", $class\->cri, " !\en" \& } \& } .Ve .PP Maintenant, lorsque nous appelons \f(CW\*(C`Boeuf\->fait\*(C'\fR, \f(CW$class\fR vaut \f(CW\*(C`Boeuf\*(C'\fR dans \f(CW\*(C`cri\*(C'\fR. Cela permet de choisir la me\*'thode \f(CW\*(C`Boeuf\->cri\*(C'\fR qui retourne \&\f(CW\*(C`mheuu\*(C'\fR. Quelle diffe\*'rence voit-on dans la version correspondant au \f(CW\*(C`Cheval\*(C'\fR\ ? .PP .Vb 7 \& { package Cheval; \& sub cri{ "hiiii" } \& sub fait { \& my $class = shift; \& print "un $class fait ", $class\->cri, " !\en" \& } \& } .Ve .PP Seuls le nom du paquetage et le cri changent. Pouvons-nous donc partager la de\*'finition de \f(CW\*(C`fait\*(C'\fR entre le Boeuf et le Cheval ? Oui, gra\*^ce a\*` l'he\*'ritage\ ! .Sh "L'he\*'ritage" .IX Subsection "L'he'ritage" Nous allons de\*'finir un paquetage commun appele\*' \f(CW\*(C`Animal\*(C'\fR contenant la de\*'finition de \f(CW\*(C`fait\*(C'\fR\ : .PP .Vb 6 \& { package Animal; \& sub fait { \& my $class = shift; \& print "un $class fait ", $class\->cri, " !\en" \& } \& } .Ve .PP Puis nous allons demander a\*` chaque animal X\ d'he\*'riter\ X de \&\f(CW\*(C`Animal\*(C'\fR\ : .PP .Vb 4 \& { package Boeuf; \& @ISA = qw(Animal); \& sub cri { "mheuu" } \& } .Ve .PP Remarquez l'ajout du tableau \f(CW@ISA\fR. Nous y reviendrons dans un instant... .PP Qu'arrive\-t\-il maintenant lorsque nous appelons \f(CW\*(C`Boeuf\->fait\*(C'\fR\ ? .PP Tout d'abord, Perl construit la liste d'arguments. Dans ce cas, c'est juste \&\f(CW\*(C`Boeuf\*(C'\fR. Puis Perl cherche la subroutine \f(CW\*(C`Boeuf::fait\*(C'\fR. Mais elle n'existe pas alors Perl regarde le tableau d'he\*'ritage \f(CW@Boeuf::ISA\fR. Il existe et contient le seul nom \f(CW\*(C`Animal\*(C'\fR. .PP Perl cherche alors \f(CW\*(C`fait\*(C'\fR dans \f(CW\*(C`Animal\*(C'\fR, c'est a\*` dire \f(CW\*(C`Animal::fait\*(C'\fR. Comme elle existe, Perl appelle cette subroutine avec la liste d'arguments pre\*'\-calcule\*'e. .PP Dans la subroutine \f(CW\*(C`Animal::fait\*(C'\fR, \f(CW$class\fR vaut \f(CW\*(C`Boeuf\*(C'\fR (le premier et seul argument). Donc, lorsque nous arrivons a\*` \f(CW\*(C`$class\->cri\*(C'\fR, la recherche commence par \f(CW\*(C`Boeuf\->cri\*(C'\fR qui est trouve\*' au premier essai sans passage par le tableau \f(CW@ISA\fR. C\*,a marche\ ! .ie n .Sh "Quelques remarques au sujet de @ISA" .el .Sh "Quelques remarques au sujet de \f(CW@ISA\fP" .IX Subsection "Quelques remarques au sujet de @ISA" La variable magique \f(CW@ISA\fR (qui se prononce \- en anglais \- X\ is a\ X et non X\ ice-uh\ X) de\*'clare que \f(CW\*(C`Boeuf\*(C'\fR est un (X\ is a\ X) \f(CW\*(C`Animal\*(C'\fR. Notez bien que ce n'est pas une valeur mais bien un tableau ce qui permet, en de rares occasions, d'avoir plusieurs parents capables de fournir les me\*'thodes manquantes. .PP Si \f(CW\*(C`Animal\*(C'\fR a lui aussi un tableau \f(CW@ISA\fR, alors il est utilise\*' aussi. La recherche est re\*'cursive, en profondeur d'abord et de gauche a\*` droite dans chaque \f(CW@ISA\fR. Classiquement, chaque \f(CW@ISA\fR ne contient qu'un seul e\*'le\*'ment (des e\*'le\*'ments multiples impliquent un he\*'ritage multiple et donc de multiples casse\-te\*^te) ce qui de\*'finit un bel arbre d'he\*'ritage. .PP Lorsqu'on active \f(CW\*(C`use strict\*(C'\fR, on obtient un avertissement concernant \f(CW@ISA\fR puisque c'est une variable dont le nom ne contient pas explicitement un nom de paquetage et qui n'est pas de\*'clare\*'e comme une variable lexicale (via X\ my\ X). On ne peut pas en faire une variable lexicale (car elle doit appartenir au paquetage pour e\*^tre accessible au me\*'canisme d'he\*'ritage). Voici donc plusieurs moyens de ge\*'rer cela\ : .PP Le moyen le plus simple est d'inclure explicitement le nom du paquetage\ : .PP .Vb 1 \& @Boeuf::ISA = qw(Animal); .Ve .PP On peut aussi cre\*'er une variable de paquetage implicitement\ : .PP .Vb 3 \& package Boeuf; \& use vars qw(@ISA); \& @ISA = qw(Animal); .Ve .PP Si vous pre\*'fe\*'rez une me\*'thode plus oriente\*'e objet, vous pouvez changer\ : .PP .Vb 4 \& package Boeuf; \& use Animal; \& use vars qw(@ISA); \& @ISA = qw(Animal); .Ve .PP en\ : .PP .Vb 2 \& package Boeuf; \& use base qw(Animal); .Ve .PP Ce qui est tre\*`s compact. .Sh "Surcharge de me\*'thodes" .IX Subsection "Surcharge de me'thodes" Ajoutons donc un mulot qu'on peut a\*` peine entendre\ : .PP .Vb 10 \& # Paquetage Animal comme au\-dessus \& { package Mulot; \& @ISA = qw(Animal); \& sub cri { "fiiik" } \& sub fait { \& my $class = shift; \& print "un $class fait ", $class\->cri, " !\en"; \& print "[mais vous pouvez a\*` peine l'entendre !]\en"; \& } \& } \& \& Mulot\->fait; .Ve .PP Le re\*'sultat sera\ : .PP .Vb 2 \& un Mulot fait fiiik ! \& [mais vous pouvez a\*` peine l'entendre !] .Ve .PP Ici, \f(CW\*(C`Mulot\*(C'\fR a sa propre routine cri, donc \f(CW\*(C`Mulot\->fait\*(C'\fR n'appellera pas imme\*'diatement \f(CW\*(C`Animal\->fait\*(C'\fR. On appelle cela la surcharge (X\ overridding\ X en anglais). En fait, nous n'avons pas besoin du tout de dire qu'un \f(CW\*(C`Mulot\*(C'\fR est un \f(CW\*(C`Animal\*(C'\fR puisque toutes les me\*'thodes ne\*'cessaires a\*` \f(CW\*(C`fait\*(C'\fR sont de\*'finies par \f(CW\*(C`Mulot\*(C'\fR. .PP Mais maintenant nous avons duplique\*' le code de \f(CW\*(C`Animal\->fait\*(C'\fR et cela peut nous amener a\*` des proble\*`mes de maintenance. Alors, pouvons-nous l'e\*'viter\ ? Pouvons-nous dire qu'un \f(CW\*(C`Mulot\*(C'\fR fait exactement comme un autre \f(CW\*(C`Animal\*(C'\fR mais en ajoutant un commentaire en plus\ ? Oui\ ! .PP Tout d'abord, nous pouvons appeler directement la me\*'thode \&\f(CW\*(C`Animal::fait\*(C'\fR\ : .PP .Vb 10 \& # Paquetage Animal comme au\-dessus \& { package Mulot; \& @ISA = qw(Animal); \& sub cri { "fiiik" } \& sub fait { \& my $class = shift; \& Animal::fait($class); \& print "[mais vous pouvez a\*` peine l'entendre !]\en"; \& } \& } .Ve .PP Remarquez que nous sommes oblige\*'s d'inclure le parame\*`tre \f(CW$class\fR (qui doit certainement valoir \f(CW\*(C`Mulot\*(C'\fR) comme premier parame\*`tre de \f(CW\*(C`Animal::fait\*(C'\fR puisque nous n'utilisons plus l'ope\*'rateur fle\*`che. Pourquoi ne plus l'utiliser\ ? Si nous appelons \f(CW\*(C`Animal\->fait\*(C'\fR ici, le premier parame\*`tre de la me\*'thode sera \f(CW"Animal"\fR et non \f(CW"Mulot"\fR et lorsqu'on arrivera a\*` l'appel de \f(CW\*(C`cri\*(C'\fR, nous n'aurons pas la bonne classe. .PP L'invocation directe de \f(CW\*(C`Animal::fait\*(C'\fR est tout autant proble\*'matique. Que se passe-t-il si la subroutine \f(CW\*(C`Animal::fait\*(C'\fR n'existe pas et est en fait he\*'rite\*'e d'une classe mentionne\*'e dans \f(CW@Animal::ISA\fR\ ? Puisque nous n'utilisons pas l'ope\*'rateur fle\*`che, nous n'avons pas la moindre chance que cela fonctionne. .PP Notez aussi que le nom de la classe \f(CW\*(C`Animal\*(C'\fR est maintenant code\*'e explicitement pour choisir la bonne subroutine. Ce sera un proble\*`me pour celui qui changera le tableau \f(CW@ISA\fR de \f(CW\*(C`Mulot\*(C'\fR sans remarquer que \f(CW\*(C`Animal\*(C'\fR est utilise\*' explicitement dans \f(CW\*(C`fait\*(C'\fR. Ce n'est donc pas la bonne me\*'thode. .Sh "Effectuer la recherche a\*` partir d'un point diffe\*'rent" .IX Subsection "Effectuer la recherche a` partir d'un point diffe'rent" Une meilleure solution consiste a\*` demander a\*` Perl de rechercher dans la chai\*^ne d'he\*'ritage un cran plus haut\ : .PP .Vb 9 \& # Animal comme au\-dessus \& { package Mulot; \& # me\*^me @ISA et me\*^me &cri qu'au\-dessus \& sub fait { \& my $class = shift; \& $class\->Animal::fait; \& print "[mais vous pouvez a\*` peine l'entendre !]\en"; \& } \& } .Ve .PP C\*,a marche. En utilisant cette syntaxe, nous commenc\*,ons par chercher dans \&\f(CW\*(C`Animal\*(C'\fR pour trouver \f(CW\*(C`fait\*(C'\fR et nous utilisons toute la chai\*^ne d'he\*'ritage de \&\f(CW\*(C`Animal\*(C'\fR si on ne la trouve pas tout de suite. Et comme le premier argument sera \f(CW$class\fR, la me\*'thode \f(CW\*(C`fait\*(C'\fR trouve\*'e pourra e\*'ventuellement appeler \&\f(CW\*(C`Mulot::cri\*(C'\fR. .PP Mais ce n'est pas la meilleure solution. Nous avons encore a\*` coordonner le tableau \f(CW@ISA\fR et le nom du premier paquetage de recherche. Pire, si \f(CW\*(C`Mulot\*(C'\fR a plusieurs entre\*'es dans son tableau \f(CW@ISA\fR, nous ne savons pas ne\*'cessairement laquelle de\*'finit re\*'ellement \f(CW\*(C`fait\*(C'\fR. Alors, y a\-t-il une meilleure solution\ ? .Sh "Le \s-1SUPER\s0 moyen de faire des choses" .IX Subsection "Le SUPER moyen de faire des choses" En changeant la classe \f(CW\*(C`Animal\*(C'\fR par la classe \f(CW\*(C`SUPER\*(C'\fR, nous obtenons automatiquement une recherche dans toutes les \s-1SUPER\s0 classes (les classes liste\*'es dans \f(CW@ISA\fR)\ : .PP .Vb 9 \& # Animal comme au dessus \& { package Mulot; \& # me\*^me @ISA et me\*^me &cri qu'au dessus \& sub dir { \& my $class = shift; \& $class\->SUPER::fait; \& print "[mais vous pouvez a\*` peine l'entendre !]\en"; \& } \& } .Ve .PP Donc, \f(CW\*(C`SUPER::fait\*(C'\fR signifie qu'il faut chercher la subroutine \f(CW\*(C`fait\*(C'\fR dans les paquetages liste\*'s par le tableau \f(CW@ISA\fR du paquetage courant (en commenc\*,ant par le premier). Notez bien que la recherche \fIne\fR sera \fIpas\fR faite dans le tableau \f(CW@ISA\fR de \f(CW$class\fR. .Sh "Ou\*` en sommes-nous ?" .IX Subsection "Ou` en sommes-nous ?" Jusqu'ici, nous avons vu la syntaxe d'appel des me\*'thodes via la fle\*`che\ : .PP .Vb 1 \& Class\->method(@args); .Ve .PP ou son e\*'quivalent\ : .PP .Vb 2 \& $a = "Class"; \& $a\->method(@args); .Ve .PP qui construit la liste d'argument\ : .PP .Vb 1 \& ("Class", @args) .Ve .PP et essaye d'appeler\ : .PP .Vb 1 \& Class::method("Class", @args); .Ve .PP Si \f(CW\*(C`Class::method\*(C'\fR n'est pas trouve\*'e, alors le tableau \f(CW@Class::ISA\fR est utilise\*' (re\*'cursivement) pour trouver un paquetage qui propose \f(CW\*(C`method\*(C'\fR puis la me\*'thode est appele\*'e. .PP En utilisant cette simple syntaxe, nous avons des me\*'thodes de classes avec he\*'ritage (multiple), surcharge et extension. Et nous avons e\*'te\*' capable de factoriser tout le code commun tout en fournissant un moyen propre de re\*'utiliser l'imple\*'mentation avec des variantes. C'est ce que fournit le coeur de la programmation oriente\*'e objet mais les objets peuvent aussi fournir des donne\*'es d'instances que nous n'avons pas encore vues. .Sh "Un cheval est un cheval bien su\*^r... Mais n'est\-il que cela ?" .IX Subsection "Un cheval est un cheval bien su^r... Mais n'est-il que cela ?" Repartons donc du code de la classe \f(CW\*(C`Animal\*(C'\fR et de la classe \&\f(CW\*(C`Cheval\*(C'\fR\ : .PP .Vb 10 \& { package Animal; \& sub fait { \& my $class = shift; \& print "un $class fait ", $class\->cri, " !\en" \& } \& } \& { package Cheval; \& @ISA = qw(Animal); \& sub cri { "hiiii" } \& } .Ve .PP Cela permet d'appeler \f(CW\*(C`Cheval\->fait\*(C'\fR qui est en fait \f(CW\*(C`Animal::fait\*(C'\fR qui, elle\-me\*^me appelle en retour \f(CW\*(C`Cheval::cri\*(C'\fR pour obtenir le cri spe\*'cifique. Ce qui produit\ : .PP .Vb 1 \& un Cheval fait hiiii ! .Ve .PP Mais tous nos objets Cheval (Chevaux ;\-) doivent absolument e\*^tre identiques. Si j'ajoute une subroutine, tous les chevaux la partagent automatiquement. C'est tre\*`s bien pour faire des chevaux identiques mais, alors, comment faire pour distinguer les chevaux les uns des autres\ ? Par exemple, supposons que nous voulions donner un nom au premier cheval. Il nous faut un moyen de conserver son nom inde\*'pendamment des autres chevaux. .PP Nous pouvons le faire en introduisant une nouvelle notion appele\*'e X\ instance\ X. Une X\ instance\ X est ge\*'ne\*'ralement cre\*'e\*'e par une classe. En Perl, n'importe quelle re\*'fe\*'rence peut e\*^tre une instance. Commenc\*,ons donc par la plus simple des re\*'fe\*'rences qui peut stocker le nom d'un cheval\ : une re\*'fe\*'rence sur un scalaire. .PP .Vb 2 \& my $nom = "Mr. Ed"; \& my $parleur = \e$nom; .Ve .PP Maintenant \f(CW$parleur\fR est une re\*'fe\*'rence vers ce qui sera une donne\*'e spe\*'cifique de l'instance (le nom). L'e\*'tape finale consiste a\*` la transformer en une vraie instance gra\*^ce a\*` l'ope\*'rateur appele\*' \f(CW\*(C`bless\*(C'\fR (\fIbe\*'nir\fR ou \&\fIconsacrer\fR en anglais)\ : .PP .Vb 1 \& bless $parleur, Cheval; .Ve .PP Cet ope\*'rateur associe le paquetage nomme\*' \f(CW\*(C`Cheval\*(C'\fR a\*` ce qui est pointe\*' par la re\*'fe\*'rence. A\*` partir de ce moment, on peut dire que \f(CW$parleur\fR est une instance de \f(CW\*(C`Cheval\*(C'\fR. C'est a\*` dire que c'est un \f(CW\*(C`Cheval\*(C'\fR spe\*'cifique. La re\*'fe\*'rence en tant que telle n'est pas modifie\*'e et on peut continuer a\*` l'utiliser avec les ope\*'rateurs traditionnels de de\*'re\*'fe\*'rencement. .Sh "Appel d'une me\*'thode d'instance" .IX Subsection "Appel d'une me'thode d'instance" L'appel de me\*'thodes via l'ope\*'rateur fle\*`che peut e\*^tre utilise\*' sur des instances exactement comme on le fait avec un nom de paquetage (classe). Donc, cherchons le cri que \f(CW$parleur\fR fait\ : .PP .Vb 1 \& my $bruit = $parleur\->cri; .Ve .PP Pour appeler \f(CW\*(C`cri\*(C'\fR, Perl remarque tout d'abord que \f(CW$parleur\fR est une re\*'fe\*'rence consacre\*'e (via \fIbless()\fR) et donc une instance. Ensuite, il construit la liste des arguments qui, dans ce cas, n'est que \f(CW$parleur\fR. (Plus tard, nous verrons que les autres arguments suivent la variable d'instance exactement comme avec les classes.) .PP Maintenant la partie inte\*'ressante\ : Perl re\*'cupe\*`re la classe ayant consacre\*'e l'instance, dans notre cas \f(CW\*(C`Cheval\*(C'\fR, et l'utilise pour trouver la subroutine a\*` appeler. Dans notre cas, \f(CW\*(C`Cheval::cri\*(C'\fR est trouve\*'e directement (sans utiliser d'he\*'ritage) et cela nous ame\*`ne a\*` l'appel finale de la subroutine\ : .PP .Vb 1 \& Cheval::cri($parleur) .Ve .PP Remarquez que le premier parame\*`tre est bien l'instance et non le nom de la classe comme auparavant. Nous obtenons \f(CW\*(C`hiiii\*(C'\fR comme valeur de retour et cette valeur est stocke\*'e dans la variable \f(CW$bruit\fR. .PP Si \f(CW\*(C`Cheval::cri\*(C'\fR n'avait pas existe\*', nous aurions e\*'te\*' oblige\*' d'explorer \&\f(CW@Cheval::ISA\fR pour y rechercher cette subroutine dans l'une des super-classes exactement comme avec les me\*'thodes de classes. La seule diffe\*'rence entre une me\*'thode de classe et une me\*'thode d'instance est le premier argument qui est soit un nom de classe (une chai\*^ne) soit une instance (une re\*'fe\*'rence consacre\*'e). .Sh "Acce\*`s aux donne\*'es d'instance" .IX Subsection "Acce`s aux donne'es d'instance" Puisque nous avons une instance comme premier parame\*`tre, nous pouvons acce\*'der aux donne\*'es spe\*'cifiques de l'instance. Dans notre cas, ajoutons un moyen d'obtenir le nom\ : .PP .Vb 8 \& { package Cheval; \& @ISA = qw(Animal); \& sub cri { "hiiii" } \& sub nom { \& my $self = shift; \& $$self; \& } \& } .Ve .PP Maintenant, appelons cette me\*'thode\ : .PP .Vb 1 \& print $parleur\->nom, " fait ", $parleur\->cri, "\en"; .Ve .PP Dans \f(CW\*(C`Cheval::nom\*(C'\fR, le tableau \f(CW@_\fR contient juste \f(CW$parleur\fR que \f(CW\*(C`shift\*(C'\fR stocke dans \f(CW$self\fR. (Il est classique de de\*'piler le premier parame\*`tre dans une variable nomme\*'e \f(CW$self\fR pour les me\*'thodes d'instance. Donc conservez cela tant que vous n'avez pas de bonnes raisons de faire autrement.) Puis, \f(CW$self\fR est de\*'re\*'fe\*'rence\*' comme un scalaire pour obtenir \f(CW\*(C`Mr. Ed\*(C'\fR. Le re\*'sultat sera\ : .PP .Vb 1 \& Mr. Ed fait hiiii .Ve .Sh "Comment fabriquer un cheval" .IX Subsection "Comment fabriquer un cheval" Bien su\*^r, si nous construisons tous nos chevaux a\*` la main, nous ferons des erreurs de temps en temps. Nous violons aussi l'un des principes de la programmation oriente\*'e objet puisque les X\ entrailles\ X d'un cheval sont visibles. C'est bien si nous sommes ve\*'te\*'rinaire pas si nous sommes de simples proprie\*'taires de chevaux. Laissons donc la classe Cheval fabriquer elle\-me\*^me un nouveau cheval\ : .PP .Vb 10 \& { package Cheval; \& @ISA = qw(Animal); \& sub cri { "hiiii" } \& sub nom { \& my $self = shift; \& $$self; \& } \& sub nomme { \& my $class = shift; \& my $nom = shift; \& bless \e$nom, $class; \& } \& } .Ve .PP Maintenant, gra\*^ce a\*` la me\*'thode \f(CW\*(C`nomme\*(C'\fR, nous pouvons cre\*'er un cheval\ : .PP .Vb 1 \& my $parleur = Cheval\->nomme("Mr. Ed"); .Ve .PP Remarquez que nous sommes revenus a\*` une me\*'thode de classe donc les deux arguments de \f(CW\*(C`Cheval::nomme\*(C'\fR sont \f(CW\*(C`Cheval\*(C'\fR et \f(CW\*(C`Mr. Ed\*(C'\fR. L'ope\*'rateur \&\f(CW\*(C`bless\*(C'\fR en plus de consacrer \f(CW$nom\fR retourne une re\*'fe\*'rence a\*` \f(CW$nom\fR qui est parfaite comme valeur de retour. Et c'est comme cela qu'on construit un cheval. .PP Ici, nous avons appele\*' le constructeur \f(CW\*(C`nomme\*(C'\fR ce qui indique que l'argument de ce constructeur est le nom de ce \f(CW\*(C`Cheval\*(C'\fR particulier. Vous pouvez utiliser diffe\*'rents constructeurs avec diffe\*'rents noms pour avoir des moyens diffe\*'rents de X\ donner naissance\ X a\*` un objet. En revanche, vous constaterez que de nombreuses personnes qui sont venues a\*` Perl a\*` partir de langages plus limite\*'s n'utilisent qu'un seul constructeur appele\*' \f(CW\*(C`new\*(C'\fR avec plusieurs fac\*,ons d'interpre\*'ter ses arguments. Tous les styles sont corrects tant que vous documentez (et vous le ferez, n'est\-ce pas\ ?) le moyen de donner naissance a\*` votre objet. .Sh "He\*'ritage de constructeur" .IX Subsection "He'ritage de constructeur" Mais y a\-t-il quelque chose de spe\*'cifique au \f(CW\*(C`Cheval\*(C'\fR dans cette me\*'thode\ ? Non. Par conse\*'quent, c'est la me\*^me chose pour construire n'importe quoi qui he\*'rite d'un \f(CW\*(C`Animal\*(C'\fR. Plac\*,ons donc cela dans \&\f(CW\*(C`Animal\*(C'\fR\ : .PP .Vb 10 \& { package Animal; \& sub fait { \& my $class = shift; \& print "un $class fait ", $class\->cri, " !\en" \& } \& sub nom { \& my $self = shift; \& $$self; \& } \& sub nomme { \& my $class = shift; \& my $nom = shift; \& bless \e$nom, $class; \& } \& } \& { package Cheval; \& @ISA = qw(Animal); \& sub cri { "hiiii" } \& } .Ve .PP Bon. Mais que se passe-t-il si nous appelons \f(CW\*(C`fait\*(C'\fR depuis une instance\ ? .PP .Vb 2 \& my $parleur = Cheval\->nomme("Mr. Ed"); \& $parleur\->fait; .Ve .PP Nous obtenons le texte suivant\ : .PP .Vb 1 \& un Cheval=SCALAR(0xaca42ac) fait hiiii ! .Ve .PP Pourquoi\ ? Parce que la routine \f(CW\*(C`Animal::fait\*(C'\fR s'attend a\*` recevoir un nom de classe comme premier parame\*`tre et non une instance. Lorsqu'une instance est passe\*'e, nous nous retrouvons a\*` utiliser un re\*'fe\*'rence consacre\*'e a\*` un scalaire en tant que chai\*^ne et nous obtenons ce que nous venons de voir. .Sh "Concevoir une me\*'thode qui marche aussi bien avec des instances qu'avec des classes" .IX Subsection "Concevoir une me'thode qui marche aussi bien avec des instances qu'avec des classes" Tout ce dont nous avons besoin c'est de de\*'tecter si l'appel se fait via une classe ou via une instance. Le moyen le plus simple est d'utiliser l'ope\*'rateur \&\f(CW\*(C`ref\*(C'\fR. Il retourne une chai\*^ne (le nom de la classe) lorsqu'il est applique\*' sur une re\*'fe\*'rence consacre\*'e et \f(CW\*(C`undef\*(C'\fR lorsqu'il est applique\*' a\*` une chai\*^ne (comme un nom de classe). Modifions donc la me\*'thode \f(CW\*(C`nom\*(C'\fR pour prendre cela en compte\ : .PP .Vb 6 \& sub nom { \& my $classouref = shift; \& ref $classouref \& ? $$classouref # c'est une instance, on retourne le nom \& : "un $classouref anonyme"; # c'est une classe, on retourne un nom ge\*'ne\*'rique \& } .Ve .PP Ici, l'ope\*'rateur \f(CW\*(C`?:\*(C'\fR devient le moyen de choisir entre de\*'re\*'fe\*'rencement ou chai\*^ne. Maintenant nous pouvons utiliser notre me\*'thode indiffe\*'remment avec une classe ou avec une instance. Notez que nous avons transforme\*' le premier parame\*`tre en \f(CW$classouref\fR pour indiquer ce qu'il contient\ : .PP .Vb 3 \& my $parleur = Cheval\->nomme("Mr. Ed"); \& print Cheval\->nom, "\en"; # affiche "un Cheval anonyme\en" \& print $parleur\->nom, "\en"; # affiche "Mr. Ed\en" .Ve .PP Modifions \f(CW\*(C`fait\*(C'\fR pour utiliser \f(CW\*(C`nom\*(C'\fR\ : .PP .Vb 4 \& sub fait { \& my $classouref = shift; \& print $classouref\->nom, " fait ", $classouref\->cri, "\en"; \& } .Ve .PP Et puisque \f(CW\*(C`cri\*(C'\fR fonctionne de\*'ja\*` que ce soit avec une instance ou une classe, nous avons fini\ ! .Sh "Ajout de parame\*`tres aux me\*'thodes" .IX Subsection "Ajout de parame`tres aux me'thodes" Faisons manger nos animaux\ : .PP .Vb 10 \& { package Animal; \& sub nomme { \& my $class = shift; \& my $nom = shift; \& bless \e$nom, $class; \& } \& sub nom { \& my $classouref = shift; \& ref $classouref \& ? $$classouref # c'est une instance, on retourne le nom \& : "un $classouref anonyme"; # c'est une classe, on retourne un nom ge\*'ne\*'rique \& } \& sub fait { \& my $classouref = shift; \& print $classouref\->nom, " fait ", $classouref\->cri, "\en"; \& } \& sub mange { \& my $classouref = shift; \& my $nourriture = shift; \& print $classouref\->nom, " mange $nourriture.\en"; \& } \& } \& { package Cheval; \& @ISA = qw(Animal); \& sub cri { "hiiii" } \& } \& { package Mouton; \& @ISA = qw(Animal); \& sub cri { "be\*^e\*^e\*^" } \& } .Ve .PP Essayons ce code\ : .PP .Vb 3 \& my $parleur = Cheval\->nomme("Mr. Ed"); \& $parleur\->mange("du foin"); \& Mouton\->mange("de l'herbe"); .Ve .PP qui affiche\ : .PP .Vb 2 \& Mr. Ed mange du foin. \& un Mouton anonyme mange de l'herbe. .Ve .PP Une me\*'thode d'instance avec des parame\*`tres est appele\*' avec, comme parame\*`tres, l'instance puis la liste des parame\*`tres. Donc ici, le premier appel est comme\ : .PP .Vb 1 \& Animal::mange($parleur, "du foin"); .Ve .Sh "Des instances plus inte\*'ressantes" .IX Subsection "Des instances plus inte'ressantes" Comment faire pour qu'une instance posse\*`de plus de donne\*'es\ ? Les instances les plus inte\*'ressantes sont constitue\*'es de plusieurs e\*'le\*'ments qui peuvent e\*^tre eux\-me\*^mes des re\*'fe\*'rences ou me\*^me des objets. Le moyen le plus simple pour les stocker est souvent une table de hachage. Les cle\*'s de la table de hachage servent a\*` nommer ces diffe\*'rents e\*'le\*'ments (qu'on appelle souvent X\ variables d'instance\ X ou X\ variables membres\ X) et les valeurs attache\*'es sont... les valeurs de ces e\*'le\*'ments. .PP Mais comment transformer notre cheval en une table de hachage\ ? Rappelez-vous qu'un objet est une re\*'fe\*'rence consacre\*'e. Il est tout a\*` fait possible d'utiliser une re\*'fe\*'rence consacre\*'e vers une table de hachage pluto\*^t que vers un simple scalaire a\*` partir du moment ou\*` chaque acce\*`s au contenu de cette re\*'fe\*'rence l'utilise correctement. .PP Cre\*'ons un mouton avec un nom et une couleur\ : .PP .Vb 1 \& my $mauvais = bless { Nom => "Evil", Couleur => "noir" }, Mouton; .Ve .PP Ainsi \f(CW\*(C`$mauvais\->{Nom}\*(C'\fR donne et \f(CW\*(C`Evil\*(C'\fR et \f(CW\*(C`$mauvais\->{Couleur}\*(C'\fR donne \f(CW\*(C`Noir\*(C'\fR. Mais \f(CW\*(C`$mauvais\->nom\*(C'\fR doit donner le nom et cela ne marche plus car cette me\*'thode attend une re\*'fe\*'rence vers un simple scalaire. Ce n'est pas tre\*`s grave car c'est simple a\*` corriger\ : .PP .Vb 7 \& ## dans Animal \& sub nom { \& my $classouref = shift; \& ref $classouref ? \& $classouref\->{Nom} : \& "un $classouref anonyme"; \& } .Ve .PP Bien su\*^r, \f(CW\*(C`nomme\*(C'\fR construit encore un mouton avec une re\*'fe\*'rence vers un scalaire. Corrigeons la\*` aussi\ : .PP .Vb 7 \& ## dans Animal \& sub nomme { \& my $class = shift; \& my $nom = shift; \& my $self = { Nom => $nom, Couleur => $class\->couleur_defaut }; \& bless $self, $class; \& } .Ve .PP D'ou\*` vient ce \f(CW\*(C`couleur_defaut\*(C'\fR\ ? Eh bien, puisque \f(CW\*(C`nomme\*(C'\fR ne fournit que le nom, nous devons encore de\*'finir une couleur. Nous avons donc une couleur par de\*'faut pour la classe. Pour un mouton, nous pouvons la de\*'finir a\*` blanc\ : .PP .Vb 2 \& ## dans Mouton \& sub couleur_defaut { "blanc" } .Ve .PP Et pour nous e\*'viter de de\*'finir une couleur par de\*'faut pour toutes les classes, nous allons de\*'finir aussi une me\*'thode ge\*'ne\*'rale dans \f(CW\*(C`Animal\*(C'\fR qui servira de X\ couleur par de\*'faut\ X par de\*'faut\ : .PP .Vb 2 \& ## dans Animal \& sub couleur_defaut { "marron" } .Ve .PP Comme \f(CW\*(C`nom\*(C'\fR et \f(CW\*(C`nomme\*(C'\fR e\*'taient les seules me\*'thodes qui utilisaient explicitement la X\ structure\ X des objets, toutes les autres me\*'thodes restent inchange\*'es et donc \f(CW\*(C`fait\*(C'\fR fonctionne encore comme avant. .Sh "Des chevaux de couleurs diffe\*'rentes" .IX Subsection "Des chevaux de couleurs diffe'rentes" Des chevaux qui sont tous de la me\*^me couleur sont ennuyeux. Alors ajoutons une me\*'thode ou deux afin de choisir la couleur. .PP .Vb 7 \& ## dans Animal \& sub couleur { \& $_[0]\->{Couleur} \& } \& sub set_couleur { \& $_[0]\->{Couleur} = $_[1]; \& } .Ve .PP Remarquez un autre moyen d'utiliser les arguments\ : \f(CW$_[0]\fR est utilise\*' directement pluto\*^t que via un \f(CW\*(C`shift\*(C'\fR. (Cela e\*'conomise un tout petit peu de temps pour quelque chose qui peut e\*^tre invoque\*' fre\*'quemment.) Maintenant, on peut choisir la couleur de Mr. Ed\ : .PP .Vb 3 \& my $parleur = Cheval\->nomme("Mr. Ed"); \& $parleur\->set_couleur("noir\-et\-blanc"); \& print $parleur\->nom, " est de couleur ", $parleur\->couleur, "\en"; .Ve .PP qui donne\ : .PP .Vb 1 \& Mr. Ed est de couleur noir\-et\-blanc .Ve .Sh "Re\*'sume\*'" .IX Subsection "Re'sume'" Ainsi, maintenant nous avons des me\*'thodes de classe, des constructeurs, des me\*'thodes d'instances, des donne\*'es d'instances, et e\*'galement des accesseurs. Mais cela n'est que le de\*'but de ce que Perl peut offrir. Nous n'avons pas non plus commence\*' a\*` parler des accesseurs qui fonctionnent a\*` la fois en lecture et en e\*'criture, des destructeurs, de la notation d'objets indirects, des sous-classes qui ajoutent des donne\*'es d'instances, des donne\*'es de classe, de la surcharge, des tests X\ isa\ X et X\ can\ X de la classe \f(CW\*(C`UNIVERSAL\*(C'\fR, et ainsi de suite. C'est couvert par le reste de la documentation de Perl. En espe\*'rant que cela vous permette de de\*'marrer, vraiment. .SH "VOIR AUSSI" .IX Header "VOIR AUSSI" Pour plus d'informations, voir perlobj (pour tous les petits de\*'tails au sujet des objets Perl, maintenant que vous avez vu les bases), perltoot (le tutoriel pour ceux qui connaissent de\*'ja\*` les objets, la page de manuel perltooc (qui traite les classes de donne\*'es), perlbot (pour les trucs et astuces), et des livres tels que l'excellent \fIObject Oriented Perl\fR de Damian Conway. .PP Citons quelques modules qui sont digne d'inte\*'re\*^t Class::Accessor, Class::Class, Class::Contract, Class::Data::Inheritable, Class::MethodMaker et Tie::SecureHash .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright (c) 1999, 2000 by Randal L. Schwartz and Stonehenge Consulting Services, Inc. Permission is hereby granted to distribute this document intact with the Perl distribution, and in accordance with the licenses of the Perl distribution; derived documents must include this copyright notice intact. .PP Portions of this text have been derived from Perl Training materials originally appearing in the \fIPackages, References, Objects, and Modules\fR course taught by instructors for Stonehenge Consulting Services, Inc. and used with permission. .PP Portions of this text have been derived from materials originally appearing in \fILinux Magazine\fR and used with permission. .SH "TRADUCTION" .IX Header "TRADUCTION" .Sh "Version" .IX Subsection "Version" Cette traduction franc\*,aise correspond a\*` la version anglaise distribue\*'e avec perl 5.8.8. Pour en savoir plus concernant ces traductions, consultez . .Sh "Traducteur" .IX Subsection "Traducteur" Paul Gaborit avec la participation de Ge\*'rard Robin . .Sh "Relecture" .IX Subsection "Relecture" Jean Forget . Ge\*'rard Delafond.