perlsub - Les sous-programmes de Perl |
my()
local()
local()
local()
perlsub - Les sous-programmes (ou subroutines) de Perl
Pour déclarer des sous-programmes :
sub NAME; # Une déclaration "en avant". sub NAME(PROTO); # idem, mais avec des prototypes sub NAME : ATTRS; # avec attributs sub NAME(PROTO) : ATTRS; # avec attributs et prototypes
sub NAME BLOCK # Une déclaration et une définition. sub NAME(PROTO) BLOCK # idem, mais avec des prototypes sub NAME : ATTRS BLOCK # avec attributs sub NAME(PROTO) : ATTRS BLOCK # avec attributs et prototypes
Pour définir un sous-programme anonyme lors de l'exécution :
$subref = sub BLOCK; # pas de prototype $subref = sub (PROTO) BLOCK; # avec prototype $subref = sub : ATTRS BLOCK; # avec attributs $subref = sub (PROTO) : ATTRS BLOCK; # avec proto et attributs
Pour importer des sous-programmes :
use MODULE qw(NAME1 NAME2 NAME3);
Pour appeler des sous-programmes :
NAME(LIST); # & est optionnel avec les parenthèses. NAME LIST; # Les parenthèses sont optionnelles si le # sous-programme est prédéclaré ou importé. &NAME(LIST); # Court-circuite les prototypes. &NAME; # Rend la @_ courante visible par le # sous-programme appelé.
Comme beaucoup de langages, Perl fournit des sous-programmes définis
par l'utilisateur. Ils peuvent se trouver n'importe où dans le
programme principal. Ils peuvent être chargés depuis d'autres fichiers
via les mots-clés do
, require
ou use
, ou être générés à la
volée en utilisant eval
ou des sous-programmes anonymes. Vous
pouvez même appeler une fonction indirectement en utilisant une
variable contenant son nom ou une référence à du CODE.
Le modèle de Perl pour l'appel de fonction et le renvoi de valeurs est simple : tous les paramètres sont passés aux fonctions comme une simple liste de scalaires, et toutes les fonctions renvoient de la même manière à leur appelant une simple liste de scalaires. Tout tableau ou hachage dans ces listes d'appel et de retour s'effondreront, perdant leur identité -- mais vous pouvez toujours utiliser le passage par référence à la place pour éviter cela. Les listes d'appel ou de retour peuvent contenir autant d'éléments scalaires que vous le désirez (une fonction sans instruction de retour explicite est souvent appelée un sous-programme, mais il n'y a vraiment pas de différence du point de vue de Perl).
Tous les arguments passés à la routine se retrouvent dans le tableau
@_
. Ainsi, si vous appelez une fonction avec deux arguments,
ceux-ci seront stockés dans $_[0]
et $_[1]
. Le tableau @_
est
un tableau local, mais ses éléments sont des alias pour les véritables
paramètres scalaires. En particulier, si un élément $_[0]
est mis à
jour, l'argument correspondant est mis à jour (ou bien une erreur se
produit s'il n'est pas modifiable). Si un argument est un élément de
tableau ou de hachage qui n'existait pas lors de l'appel de la
fonction, cet élément est créé seulement lorsque (et si) il est
modifié ou si on y fait référence (certaines versions précédentes de
Perl créaient l'élément qu'il soit ou non affecté). L'affectation à la
totalité du tableau @_
retire les alias, et ne met à jour aucun
argument.
Une instruction return
peut être utilisée pour sortir d'un
sous-programme, en spécifiant éventuellement une valeur de retour, qui
sera évaluée dans le contexte approprié (liste, scalaire ou vide)
selon le contexte d'appel du sous-programme. Si vous ne spécifiez
aucune valeur de retour, le sous-programme retourne une liste vide
dans un contexte de liste, la valeur indéfinie dans un contexte
scalaire et rien du tout dans un contexte vide. Si vous retournez un
ou plusieurs aggrégats (tableau ou table de hachage), ils seront tous
applatis en une seule grande liste.
Si aucun return
n'est trouvé et si la dernière instruction est une
expression, sa valeur est retournée. Si la dernière instruction est
une structure de contrôle de boucle comme foreach
ou while
, la
valeur retournée est non spécifiée. Un sous-programme vide retourne
une liste vide.
Perl n'a pas de paramètres formels nommés. En pratique tout ce que
vous avez à faire est d'affecter à une liste my()
les
contenant. Les variables que vous utilisez dans la fonction et qui ne
sont pas déclarées comme privées sont des variables globales. Pour des
détails sanglants sur la création de variables privées, voir
Variables privées via my() et Valeurs temporaires via local(). Pour créer des environnement protégés pour un ensemble de
fonctions dans un paquetage séparé (et probablement un fichier
séparé), voir Paquetages dans la page de manuel perlmod.
Exemple :
sub max { my $max = shift(@_); foreach $foo (@_) { $max = $foo if $max < $foo; } return $max; } $bestday = max($mon,$tue,$wed,$thu,$fri);
Exemple :
# obtient une ligne, en y combinant les lignes la continuant qui # débutent par un blanc
sub get_line { $thisline = $lookahead; # Variables globales !! LINE: while (defined($lookahead = <STDIN>)) { if ($lookahead =~ /^[ \t]/) { $thisline .= $lookahead; } else { last LINE; } } return $thisline; }
$lookahead = <STDIN>; # obtient la première ligne while (defined($line = get_line()) { ... }
Affectez à une liste de variables privées pour nommer vos arguments :
sub maybeset { my($key, $value) = @_; $Foo{$key} = $value unless $Foo{$key}; }
Puisque l'affectation copie les valeurs, ceci a aussi pour effet de
transformer l'appel par référence en appel par valeur. Autrement, une
fonction est libre de faire des modifications de @_
sur place et de
changer les valeurs de son appelant.
upcase_in($v1, $v2); # ceci change $v1 et $v2 sub upcase_in { for (@_) { tr/a-z/A-Z/ } }
Vous n'avez pas le droit de modifier les constantes de cette façon, bien sûr. Si un argument était en vérité un littéral et que vous essayiez de le changer, vous lèveriez une exception (probablement fatale). Par exemple, ceci ne fonctionnera pas :
upcase_in("frederick");
Ce serait bien plus sûr si la fonction upcase_in()
était écrite de
façon à renvoyer une copie de ses paramètres au lieu de les changer
sur place :
($v3, $v4) = upcase($v1, $v2); # cela ne change pas $v1 et $v2 sub upcase { return unless defined wantarray; # contexte vide, ne fait rien my @parms = @_; for (@parms) { tr/a-z/A-Z/ } return wantarray ? @parms : $parms[0]; }
Notez comment cette fonction (non prototypée) ne se soucie pas qu'on
lui ait passé de vrais scalaires ou des tableaux. Perl voit tous les
arguments comme une grosse et longue liste plate de paramètres dans
@_
. C'est un domaine dans lequel brille le style simple de passage
d'arguments de Perl. La fonction upcase()
fonctionnerait
parfaitement bien sans avoir à changer la définition de upcase()
même si nous lui donnions des choses telles que ceci :
@newlist = upcase(@list1, @list2); @newlist = upcase( split /:/, $var );
Ne vous laissez toutefois pas tenter de faire :
(@a, @b) = upcase(@list1, @list2);
Tout comme la liste plate de paramètres entrante, la liste de retour
est aussi aplatie. Donc tout ce que vous êtes parvenu à faire ici est
de tout stocker dans @a
et de vider @b
. Voir Passage par référence pour savoir comment faire autrement.
Un sous-programme peut être appelé en utilisant un préfixe &
explicite. Le &
est optionnel en Perl moderne, tout comme le sont
les parenthèses si le sous-programme a été prédéclaré. Le &
n'est
pas optionnel lorsque l'on nomme juste le sous-programme, comme
lorsqu'il est utilisé en tant qu'argument de defined()
ou de
undef(). Il n'est pas non plus optionnel lorsque vous voulez faire un
appel indirect de sous-programme avec le nom d'un sous-programme ou
une référence utilisant les constructions &$subref()
ou
&{$subref}()
, bien que la notation $subref->()
résoud ce
problème. Voir la page de manuel perlref pour plus de détails à ce sujet.
Les sous-programmes peuvent être appelés de façon récursive. Si un
sous-programme est appelé en utilisant la forme &
, la liste
d'arguments est optionnelle, et si elle est omise, aucun tableau @_
n'est mis en place pour le sous-programme : le tableau @_
au moment
de l'appel est visible à la place dans le sous-programme. C'est un
mécanisme d'efficacité que les nouveaux utilisateurs pourraient
préférer éviter.
&foo(1,2,3); # passe trois arguments foo(1,2,3); # idem
foo(); # passe une liste nulle &foo(); # idem
&foo; # foo() obtient les arguments courants, comme foo(@_) !! foo; # comme foo() SI le sous-programme foo est # prédéclaré, sinon "foo"
Non seulement la forme &
rend la liste d'arguments optionnelle,
mais elle désactive aussi toute vérification de prototype sur les
arguments que vous fournissez. C'est en partie pour des raisons
historiques, et en partie pour avoir une façon pratique de tricher si
vous savez ce que vous êtes en train de faire. Voir Prototypes
ci-dessous.
Les sous-programme dont les noms sont entièrement en majuscules sont
réservées pour le noyau de Perl, tout comme les modules dont les noms
sont entièrement en minuscules. Une fonction entièrement en majuscules
est une convention informelle signifiant qu'elle sera appelée
indirectement par le système d'exécution lui-même, habituellement en
réponse à un événement. Les sous-programmes qui font des choses
spéciales prédéfinies sont entre autres AUTOLOAD
, CLONE
et
DESTROY
-- plus toutes les fonctions mentionnées dans la page de manuel perltie et
la page de manuel PerlIO::via.
Les sous-programmes BEGIN
, CHECK
, INIT
et END
sont plutôt
des blocs spéciaux, de code, nommés, qui peuvent apparaître plusieurs
fois dans un paquetage et qu'il vous est impossible d'appeler
explicitement. Voir BEGIN, CHECK, INIT et END dans la page de manuel perlmod.
my()
Synopsis:
my $foo; # déclare $foo locale lexicalement my (@wid, %get); # déclare une liste de variables locale my $foo = "flurp"; # déclare $foo lexical, et l'initialise my @oof = @bar; # déclare @oof lexical, et l'initialise my $x : Foo = $y; # similaire, avec application d'un attribut
AVERTISSEMENT : l'usage de listes d'attributs sur les déclarations
my
est expérimental. La sémantique précise et l'interface associée
sont sujettes à changement. Voir attributes et
la page de manuel Attribute::Handlers.
L'opérateur my
déclare que les variables listées doivent être
confinées lexicalement au bloc où elles se trouvent, dans la
conditionnelle (if/unless/elsif/else
), la boucle
(for/foreach/while/until/continue
), le sous-programme, l'eval
,
ou le fichier exécuté, requis ou utilisé via do/require/use
. Si
plus d'une valeur est listée, la liste doit être placée entre
parenthèses. Tous les éléments listés doivent être des lvalues
légales. Seuls les identifiants alphanumériques peuvent avoir une
portée lexicale -- pour l'instant1, les identifiants magiques
prédéfinis comme $/
peuvent, à la place, être localisés par
local
.
Contrairement aux variables dynamiques créées par l'opérateur
local
, les variables lexicales déclarées par my
sont totalement
cachées du monde extérieur, y compris de tout sous-programme
appelé. Cela est vrai s'il s'agit du même sous-programme rappelé
depuis lui-même ou depuis un autre endroit -- chaque appel obtient sa
propre copie.
Ceci ne veut pas dire qu'une variable my()
déclarée dans une portée
lexicale englobante statiquement serait invisible. Seules les portées
dynamiques sont rétrécies. Par exemple, la fonction bumpx()
ci-dessous a accès à la variable lexicale $x
car le my
et le
sub
se sont produits dans la même portée, probablement la portée du
fichier.
my $x = 10; sub bumpx { $x++ }
Un eval()
, toutefois, peut voir les variables lexicales de la
portée dans laquelle il est évalué, tant que les noms ne sont pas
cachés par des déclarations à l'intérieur de l'eval()
lui-même. Voir la page de manuel perlref.
La liste de paramètres de my()
peut être affectée si on le désire, ce
qui vous permet d'initialiser vos variables (si aucune valeur initiale
n'est donnée à une variable particulière, celle-ci est créé avec la
valeur indéfinie). Ceci est utilisé couramment pour nommer les
paramètres d'entrée d'un sous-programme. Exemples :
$arg = "fred"; # variable "globale" $n = cube_root(27); print "$arg thinks the root is $n\n"; fred thinks the root is 3
sub cube_root { my $arg = shift; # le nom n'importe pas $arg **= 1/3; return $arg; }
Le my
est simplement un modificateur sur quelque chose que vous
pourriez affecter. Donc lorsque vous affectez les variable dans sa
liste d'arguments, le my
ne change pas le fait que ces variables
soient vues comme un scalaire ou un tableau. Donc
my ($foo) = <STDIN>; # FAUX ? my @FOO = <STDIN>;
les deux fournissent un contexte de liste à la partie droite, tandis que
my $foo = <STDIN>;
fournit un contexte scalaire. Mais ce qui suit ne déclare qu'une seule variable :
my $foo, $bar = 1; # FAUX
Cela a le même effet que
my $foo; $bar = 1;
La variable déclarée n'est pas introduite (n'est pas visible) avant la fin de l'instruction courante. Ainsi,
my $x = $x;
peut être utilisé pour initialiser une nouvelle variable $x avec la valeur de l'ancienne $x, et l'expression
my $x = 123 and $x == 123
est fausse à moins que l'ancienne variable $x ait la valeur 123
.
Les portées lexicales de structures de contrôle ne sont pas précisément liées aux accolades qui délimitent le bloc qu'elles contrôlent ; les expressions de contrôle font aussi partie de cette portée. Ainsi, dans la boucle
while (my $line =<>) { $line = lc $line; } continue { print $line; }
la portée de $line s'étend à partir de sa déclaration et sur tout le
reste de la boucle (y compris la clause continue
), mais pas
au-delà. De façon similaire, dans la conditionnelle
if ((my $answer = <STDIN>) =~ /^yes$/i) { user_agrees(); } elsif ($answer =~ /^no$/i) { user_disagrees(); } else { chomp $answer; die "'$answer' is neither 'yes' nor 'no'"; }
la portée de $answer s'étend à partir de sa déclaration et sur tout le
reste de la conditionnelle, y compris les clauses elsif
et else
,
s'il y en a, mais pas au-delà. Voir Instructions simples dans la page de manuel perlsyn
pour plus d'informations sur la portée des variables dans des
instructions avec modificateurs.
La boucle foreach
a pour défaut de donner une portée dynamiquement
a sa variable d'index à la manière de local
. Toutefois, si la
variable d'index est préfixée par le mot-clé my
, ou s'il existe
déjà un lexical ayant ce nom dans la porté, alors un nouveau lexical
est créé à la place. Ainsi dans la boucle
for my $i (1, 2, 3) { some_function(); }
la portée de $i s'étend jusqu'à la fin de la boucle, rendant la valeur
de $i inaccessible dans some_function()
.
Certains utilisateurs pourraient désirer encourager l'usage de variables à portée lexicale. Comme aide pour intercepter les utilisations implicites de variables de paquetage, qui sont toujours globales, si vous dites
use strict 'vars';
alors toute variable mentionnée à partir de là jusqu'à la fin du bloc
doit soit se référer à une variable lexicale, soit être prédéclarée
via our
ou use vars
, soit encore être totalement qualifiée avec
le nom du paquetage. Autrement, une erreur de compilation se
produit. Un bloc interne pourrait contrer ceci par no strict
'vars'
.
Un my
a un effet à la fois à la compilation et lors de
l'exécution. Lors de la compilation, le compilateur le remarque. La
principale utilité de ceci est de faire taire use strict 'vars'
,
mais c'est aussi essentiel pour la génération de fermetures telle que
détaillée dans la page de manuel perlref. L'initialisation effective est toutefois
retardée jusqu'à l'exécution, de façon à ce qu'elle soit exécutée au
moment approprié, par exemple à chaque fois qu'une boucle traversée.
Les variables déclarées avec my
ne font pas partie d'un paquetage
et ne sont par conséquent jamais totalement qualifiée avec le nom du
paquetage. En particulier, vous n'avez pas le droit d'essayer de
rendre lexicale une variable de paquetage (ou toute autre variable
globale) :
my $pack::var; # ERREUR ! Syntaxe Illégale my $_; # aussi illégal (pour le moment)
En fait, une variable dynamique (aussi connue sous le nom de variable
de paquetage ou variable globale) est toujours accessible en utilisant
la notation totalement qualifiée ::
même lorsqu'un lexical de même
nom est lui aussi visible :
package main; local $x = 10; my $x = 20; print "$x and $::x\n";
Ceci affichera 20
et 10
.
Vous pouvez déclarer les variables my
dans la portée extrême d'un
fichier pour cacher tous ces identifants du monde extérieur à ce
fichier. Cela est similaire en esprit aux variables statiques de C
quand elles sont utilisées au niveau du fichier. Faire cela avec un
sous-programme requiert l'usage d'une fermeture (une fonction anonyme
qui accède aux lexicaux qui l'entourent). Si vous voulez créer un
sous-programme privé qui ne peut pas être appelé en-dehors de ce bloc,
il peut déclarer une variable lexicale conenant une référence anonyme
de sous-programme :
my $secret_version = '1.001-beta'; my $secret_sub = sub { print $secret_version }; &$secret_sub();
Tant que la référence n'est jamais renvoyée par aucune fonction du
module, aucun module extérieur ne peut voir le sous-programme, car son
nom n'est dans la table de symboles d'aucun paquetage. Souvenez-vous
qu'il n'est jamais VRAIMENT appelé $some_pack::secret_version
ou
quoi que ce soit ; c'est juste $secret_version, non qualifié et non
qualifiable.
Ceci ne fonctionne pas avec les méthodes d'objets, toutefois ; toutes les méthodes d'objets doivent se trouver dans la table de symboles d'un paquetage quelconque pour être trouvées. Voir Modèles de Fonctions dans la page de manuel perlref pour une méthode permettant de contourner ceci.
Le fait qu'une variable lexicale ait une portée lexicale (aussi
appelée statique) égale au bloc qui la contient, à l'eval
, ou au
FICHIER do
, ne veut pas dire que cela fonctionne à l'intérieur
d'une fonction comme une variable statique en C. Cela marche plutôt
comme une variable auto de C, mais avec un nettoyage de la mémoire (un
rammasse-miettes) implicite.
Contrairement aux variables locales en C ou en C++, les variables lexicales de Perl ne sont pas nécessairement recyclées juste parce qu'on est sorti de leur portée. Si quelque chose de plus permanent est toujours conscient du lexical, il restera. Tant que quelque chose d'autre fait référence au lexical, ce lexical ne sera pas libéré -- ce qui est comme il se doit. Vous ne voudriez pas que la mémoire soit libérée tant que vous n'avez pas fini de l'utiliser, ou gardée lorsque vous en avez terminé. Le ramasse-miette automatique s'occupe de cela pour vous.
Ceci veut dire que vous pouvez passer en retour ou sauver des références à des variables lexicales, tandis que retourner un pointeur sur un auto en C est une grave erreur. Cela nous donne aussi un moyen de simuler les variables statiques de fonctions C. Voici un mécanisme donnant à une fonction des variables privées de portée lexicale ayant une durée de vie statique. Si vous désirez créer quelque chose ressemblant aux vatiables statiques de C, entourez juste toute la fonction d'un niveau de bloc supplémentaire, et mettez la variable statique hors de la fonction mais dans le bloc.
{ my $secret_val = 0; sub gimme_another { return ++$secret_val; } } # $secret_val devient désormais impossible à atteindre pour le # monde extérieur, mais garde sa valeur entre deux appels à # gimme_another
Si cette fonction est chargée par require
ou use
depuis un
fichier séparé, alors cela marchera probablement très bien. Si tout se
trouve dans le programme principal, vous devrez vous arranger pour que
le my
soit exécuté tôt, soit en mettant tout le bloc avant votre
programme principal, ou, de préférence, en plaçant simplement un
BEGIN
devant lui pour vous assurer qu'il soit exécutée avant que
votre programme ne démarre :
BEGIN { my $secret_val = 0; sub gimme_another { return ++$secret_val; } }
Voir BEGIN, CHECK, INIT et END dans la page de manuel perlmod pour en savoir plus sur la
mises en oeuvre des blocks spéciaux BEGIN
, CHECK
, INIT
et
END
.
S'ils sont déclarés au niveau de la plus grande portée (celle du fichier), alors les lexicaux fonctionnent un peu comme les variables statiques de fichier en C. Ils sont disponibles pour toutes les fonctions déclarées en dessous d'eux dans le même fichier, mais sont inaccessibles hors du fichier. Cette stratégie est parfois utilisé dans les modules pour créer des variables privées que la totalité du module peut voir.
local()
AVERTISSEMENT : en général, vous devriez utiliser my
au lieu de
local
, parce que c'est plus rapide et plus sûr. Les exceptions à
cela incluent les variables globales dont le nom est un caractère de
ponctuation, les handles de fichier globaux et les formats globaux et
la manipulation directe de la table de symboles de Perl. On utilise
local
lorsqu'on souhaite que la valeur courante d'une variable soit
visible par les sous-programmes appelés.
Synopsis :
# local-isation de valeurs local $foo; # rend $foo dynamiquement locale local (@wid, %get); # rend locales toutes les variables d'une liste local $foo = "flurp"; # rend $foo dynamique, et l'initialise local @oof = @bar; # rend @oof dynamique, et l'initialise local $hash{key} = "val"; # rend local la valeur lié à cette clé local ($cond ? $v1 : $v2); # la plupart des types de lvalues # acceptent la local-isation # local-isation de symboles local *FH; # rend locales $FH, @FH, %FH, &FH... local *merlyn = *randal; # maintenant $merlyn est vraiment $randal, # @merlyn est vraiment @randal, etc. local *merlyn = 'randal'; # IDEM : 'randal' est promu *randal local *merlyn = \$randal; # alias juste $merlyn, pas @merlyn etc
Un local()
modifie ses variables listées pour qu'elle soient
«locales» au bloc courant, à l'eval
, ou au FICHIER do
-- et à
tout sous-programme appelé depuis l'intérieur de ce bloc. Un
local()
donne juste des valeurs temporaires aux variables globales
(au paquetage). Il ne crée pas une variable locale. Ceci est connu
sous le nom de portée dynamique. La portée lexicale est créé par
my
, qui fonctionne plus comme les déclarations auto de C.
Différents types de lvalues peuvent être localisés : les éléments ou les tranches de tableaux ou de tables de hachage, éventuellement de manière conditionnelle (dans la mesure où le résultat est bien localisable), et les références symboliques. Comme pour de simples variables, cela crée de nouvelles valeurs avec une portée dynamqiue.
Si plus d'une variable est fournie à local
, elles doivent être
placées entre parenthèses. Cet opérateur fonctionne en sauvegardant
les valeurs courantes de ces variables dans sa liste d'arguments sur
une pile cachée et les restaure à la sortie du bloc, du sous-programme
ou de l'eval. Ceci veut dire que les sous-programmes appelés peuvent
aussi référencer les variables locales, mais pas les globales. La
liste d'arguments peut être affectée si l'on veut, ce qui vous permet
d'initialiser vos variables locales (si aucun initialiseur n'est donné
pour une variable locale particulière, elle est créée avec la valeur
indéfinie).
Puisque local
est une commande réalisée lors de la phase
d'exécution, elle est donc exécutée chaque fois que l'on traverse une
boucle. Par conséquent il est toujours plus efficace de localiser vos
variables en dehors de la boucle.
local()
Un local
est simplement un modificateur d'une expression donnant
une lvalue. Lorsque vous affectez une variable local
isée, le
local
ne change pas selon que sa liste est vue comme un scalaire ou
un tableau. Donc
local($foo) = <STDIN>; local @FOO = <STDIN>;
fournissent tous les deux un contexte de liste à la partie droite, tandis que
local $foo = <STDIN>;
fournit un contexte scalaire.
Si vous localisez une variable spéciale, vous lui donnez une nouvelle valeur mais sans lui faire perdre ses fonctionnalités magiques. Cela signifie que tous les effets secondaires de cette magie ont lieu avec cette nouvelle valeur.
Cela permet le fonctionnement d'un code tel que celui-ci :
# Lit tout le contenu de FILE dans $slurp { local $/ = undef; $slurp = <FILE>; }
Notez, en revanche, que cela empêche la localisation de certaines variables. Par exemple, l'instruction suivante déclenchera, dans perl 5.9.0, un appel à 'die' avec l'erreur Modification of a read-only value attempted puisque $1 est une variable magique en lecture seule :
local $1 = 2;
De manière similaire mais moins évidente, le code suivant déclenchera un 'die' en perl 5.9.0 :
sub f { local $_ = "foo"; print } for ($1) { # now $_ is aliased to $1, thus is magic and readonly f(); }
Voir la section suivante pour savoir comment palier cela.
ATTENTION : la localisation de tableaux ou de tables de hachage
liés (par tie())
ne fonctionne pas comme cela. Cela sera corrigé dans
une prochaine version de Perl. En attendant, évitez de localiser des
tableaux ou des tables de hachage liés (la localistion de éléments
individuels fonctionnent). Voir perl58delta/«Localisation de tableaux et de tables de hachage liés (par tie())» pour plus de
détails.
La construction
local $name;
crée une nouvelle entrée dans la table de symbole associé au glob
name
dans le paquetage courant. Cela signifie que toutes les
variables attachées à cette entrée ($name, @name, %name, &name et le
handle de fichier name
) sont dynamiquement réinitialisées.
En particulier, si vous voulez une nouvelle valeur pour le scalaire
par défaut $_, en évitant le problème potentiel évoqué plus haut
lorsque $_ était attaché à une valeur magique. vous devriez utiliser
local *_
au lieu de local $_
.
Une note sur local()
et les types composés est nécessaire. Quelque
chose comme local(%foo)
fonctionne en plaçant temporairement un
hachage tout neuf dans la table des symboles. L'ancien hachage est mis
de côté, mais est caché «derrière» le nouveau.
Ceci signifie que l'ancienne variable est complètement invisible via
la table des symboles (i.e. l'entrée de hachage dans le typeglob
*foo
) pendant toute la durée de la portée dynamique dans laquelle
le local()
a été rencontré. Cela a pour effet de permettre
d'occulter temporairement toute magie sur les types composés. Par
exemple, ce qui suit altèrera brièvement un hachage lié à une autre
implémentation :
tie %ahash, 'APackage'; [...] { local %ahash; tie %ahash, 'BPackage'; [.. le code appelé verra %ahash lié à 'BPackage'..] { local %ahash; [..%ahash est une hachage normal (non lié) ici..] } } [..%ahash revient à sa nature liée initiale..]
Autre exemple, une implémentation personnelle de %ENV
pourrait
avoir l'air de ceci :
{ local %ENV; tie %ENV, 'MyOwnEnv'; [..faites vos propres manipulations fantaisistes de %ENV ici..] } [..comportement normal de %ENV ici..]
Il vaut aussi la peine de prendre un moment pour expliquer ce qui se
passe lorsque vous local
isez un membre d'un type composé (i.e. un
élément de tableau ou de hachage). Dans ce cas, l'élément est
local
isé par son nom. Cela veut dire que lorsque la portée du
local()
se termine, la valeur sauvée sera restaurée dans l'élément
du hachage dont la clé a été nommée dans le local()
, ou dans
l'élément du tableau dont l'index a été nommé dans le local()
. Si
cet élément a été effacé pendant que le local()
faisait effet
(e.g. par un delete()
dans un hachage ou un shift()
d'un
tableau), il reprendra vie, étendant potentiellement un tableau et
remplissant les éléments intermédiaires avec undef
. Par exemple, si
vous dites
%hash = ( 'This' => 'is', 'a' => 'test' ); @ary = ( 0..5 ); { local($ary[5]) = 6; local($hash{'a'}) = 'drill'; while (my $e = pop(@ary)) { print "$e . . .\n"; last unless $e > 3; } if (@ary) { $hash{'only a'} = 'test'; delete $hash{'a'}; } } print join(' ', map { "$_ $hash{$_}" } sort keys %hash),".\n"; print "The array has ",scalar(@ary)," elements: ", join(', ', map { defined $_ ? $_ : 'undef' } @ary),"\n";
Perl affichera
6 . . . 4 . . . 3 . . . This is a test only a test. The array has 6 elements: 0, 1, 2, undef, undef, 5
Le comportement de local()
sur des membres inexistants de types
composites est sujet à changements à l'avenir.
AVERTISSEMENT : les sous-programmes en partie gauche (en lvalue) sont encore expérimentaux et leur implémentation est sujette à changements dans les futures versions de Perl.
Il est possible de retourner une valeur modifiable depuis un sous-programme. Pour ce faire, vous devez déclarer que le sous-programme retourne une lvalue.
my $val; sub canmod : lvalue { # return $val; cela ne fonction pas, ne dites pas "return" $val; } sub nomod { $val; } canmod() = 5; # modifie $val nomod() = 5; # ERREUR
Le contexte scalaire ou de liste pour le sous-programme et la partie droite de l'affectation est déterminé comme si l'appel au sous-programme était remplacé par un scalaire. Par exemple, si l'on considère :
data(2,3) = get_data(3,4);
Les deux sous-programmes sont appelées ici dans un contexte scalaire, tandis que dans :
(data(2,3)) = get_data(3,4);
et dans :
(data(2),data(3)) = get_data(3,4);
tous les sous-programmes sont appelés dans un contexte de liste.
Vous ne devez pas utiliser le mot-clé return et vous devez passez la valeur de sortie avant qu'elle soit hors de portée (voir le commentaire dans l'exemple plus haut). Ce n'est pas habituellement un problème mais cela empêche tout de même un return explicite dans une boucle qui est pourtant parfois bien pratique.
Cela ne respecte pas l'encapsulation. Un mutateur normal vérifie la valeur fournie avant de l'affecter à l'attribut qu'il protège. Un sous-programme lvalue ne permet pas cela. Considérez le code suivant :
my $some_array_ref = []; # protégé par un mutateur ?? sub set_arr { # mutateur normal my $val = shift; die("expected array, you supplied ", ref $val) unless ref $val eq 'ARRAY'; $some_array_ref = $val; } sub set_arr_lv : lvalue { # mutateur par lvalue $some_array_ref; } # set_arr_lv ne peut pas empêcher cela ! set_arr_lv() = { a => 1 };
AVERTISSEMENT : le mécanisme décrit dans cette section était à l'origine la seule façon de simuler un passage par référence dans les anciennes versions de Perl. Même si cela fonctionne toujours très bien dans les version modernes, le nouveau mécanisme de référencement est généralement plus facile à utiliser. Voir plus bas.
Parfois, vous ne voulez pas passer la valeur d'un tableau à un
sous-programme mais plutôt son nom, pour que le sous-programme puisse
modifier sa copie globale plutôt que de travailler sur une copie
locale. En perl, vous pouvez vous référer à tous les objets d'un nom
particulier en préfixant ce nom par une étoile : *foo
. Cela est
souvent connu sous le nom de «typeglob», car l'étoile devant peut être
conçue comme un caractère générique correspondant à tous les drôles de
caractères préfixant les variables et les sous-programmes et le reste.
Lorsqu'il est évalué, le typeglob produit une valeur scalaire qui
représente tous les objets portant ce nom, y compris tous les handles
de fichiers, les formats, ou les sous-programmes. Quand on l'affecte,
le nom mentionné se réfère alors à la valeur *
qui lui a été
affectée, quelle qu'elle soit. Exemple :
sub doubleary { local(*someary) = @_; foreach $elem (@someary) { $elem *= 2; } } doubleary(*foo); doubleary(*bar);
Les scalaires sont déjà passés par référence, vous pouvez donc
modifier les arguments scalaires sans utiliser ce mécanisme en vous
référant explicitement à $_[0]
, etc. Vous pouvez modifier tous les
éléments d'un tableau en passant tous les éléments comme des
scalaires, mais vous devez utiliser le mécanisme *
(ou le mécanisme
de référencement équivalent) pour effectuer des push
, des pop
,
ou changer la taille d'un tableau. Il sera certainement plus rapide de
passer le typeglob (ou la référence).
Même si vous ne voulez pas modifier un tableau, ce mécanisme est utile pour passer des tableaux multiples dans une seule LIST, car normalement le mécanisme LIST fusionnera toutes les valeurs de tableaux et vous ne pourrez plus en extraire les tableaux individuels. Pour plus de détails sur les typeglobs, voir Typeglobs et handles de fichiers dans la page de manuel perldata.
local()
Malgré l'existence de my
, il y a encore trois endroits où
l'opérateur local
brille toujours. En fait, en ces trois endroits,
vous devez utiliser local
à la place de my
.
Les variables globales, comme @ARGV
ou les variables de
ponctuation, doivent être local
isées avec local()
. Ce bloc lit
dans /etc/motd, et le découpe en morceaux, séparés par des lignes de
signes égal, qui sont placés dans @Fields
.
{ local @ARGV = ("/etc/motd"); local $/ = undef; local $_ = <>; @Fields = split /^\s*=+\s*$/; }
Il est important en particulier de local
iser $_ dans toute routine
qui l'affecte. Surveillez les affectations implicites dans les
conditionnelles while
.
Une fonction ayant besoin de son propre handle de fichier doit
utiliser local()
sur le typeglob complet. Ceci peut être utilisé
pour créer de nouvelles entrées dans la table des symboles :
sub ioqueue { local (*READER, *WRITER); # pas my ! pipe (READER, WRITER) or die "pipe: $!"; return (*READER, *WRITER); } ($head, $tail) = ioqueue();
Voir le module Symbol pour une façon de créer des entrées de table de symboles anonymes.
Puisque l'affectation d'une référence à un typeglob crée un alias, ceci peut être utilisé pour créer ce qui est effectivement une fonction locale, ou au moins un alias local.
{ local *grow = \&shrink; # seulement jusqu'à la fin de # l'existence de ce bloc grow(); # appelle en fait shrink() move(); # si move() grandit, il rétrécit # aussi } grow(); # récupère le vrai grow()
Voir Modèles de fonctions dans la page de manuel perlref pour plus de détails sur la manipulation des fonctions par leur nom de cette manière.
Vous voulez changer temporairement un seul élément d'un tableau ou d'un hachage.Vous pouvez local
iser juste un élément d'un aggrégat.
Habituellement, cela est fait dynamiquement :
{ local $SIG{INT} = 'IGNORE'; funct(); # impossible à interrompre } # la possibilité d'interrompre est restaurée ici
Mais cela fonctionne aussi sur les aggrégats déclarés lexicalement. Avant la version 5.005, cette opération pouvait parfois mal se conduire.
Si vous voulez passer plus d'un tableau ou d'un hachage à une fonction -- ou les renvoyer depuis elle -- de façon qu'ils gardent leur intégrité, vous allez devoir alors utiliser un passage par référence explicite. Avant de faire cela, vous avez besoin de comprendre les références telles qu'elles sont détaillées dans la page de manuel perlref. Cette section n'aura peut-être pas beaucoup de sens pour vous sans cela.
Voici quelques exemples simples. Tout d'abord, passons plusieurs
tableaux à une fonction puis faisons-lui faire des pop
sur eux, et
retourner une nouvelle liste de tous leurs derniers éléments :
@tailings = popmany ( \@a, \@b, \@c, \@d );
sub popmany { my $aref; my @retlist = (); foreach $aref ( @_ ) { push @retlist, pop @$aref; } return @retlist; }
Voici comment vous pourriez écrire une fonction retournant une liste des clés apparaissant dans tous les hachages qu'on lui passe :
@common = inter( \%foo, \%bar, \%joe ); sub inter { my ($k, $href, %seen); # locals foreach $href (@_) { while ( $k = each %$href ) { $seen{$k}++; } } return grep { $seen{$_} == @_ } keys %seen; }
Jusque là, nous utilisons juste le mécanisme normal de retour d'une liste. Que se passe-t-il si vous voulez passer ou retourner un hachage ? Eh bien, si vous n'utilisez que l'un d'entre eux, ou si vous ne voyez pas d'inconvénient à ce qu'ils soient concaténés, alors la convention d'appel normale est valable, même si elle coûte un peu cher.
C'est ici que les gens commencent à avoir des problèmes :
(@a, @b) = func(@c, @d); ou (%a, %b) = func(%c, %d);
Cette syntaxe ne fonctionnera tout simplement pas. Elle définit juste
@a
ou %a
et vide @b
ou %b
. De plus, la fonction n'a pas
obtenu deux tableaux ou hachages séparés : elle a eu une longue liste
dans @_
, comme toujours.
Si vous pouvez vous arranger pour que tout le monde règle cela par des références, cela fait du code plus propre, même s'il n'est pas très joli à regarder (phrase louche, NDT). Voici une fonction qui prend deux références de tableau comme arguments et renvoit les deux éléments de tableau dans l'ordre du nombre d'éléments qu'ils contiennent :
($aref, $bref) = func(\@c, \@d); print "@$aref has more than @$bref\n"; sub func { my ($cref, $dref) = @_; if (@$cref > @$dref) { return ($cref, $dref); } else { return ($dref, $cref); } }
Il s'avère en fait que vous pouvez aussi faire ceci :
(*a, *b) = func(\@c, \@d); print "@a has more than @b\n"; sub func { local (*c, *d) = @_; if (@c > @d) { return (\@c, \@d); } else { return (\@d, \@c); } }
Ici nous utilisons les typeglobs pour faire un aliasing de la table
des symboles. C'est un peu subtile, toutefois, et en plus cela ne
fonctionnera pas si vous utilisez des variables my
, puisque seules
les variables globales (et les local
es en fait) sont dans la table
des symboles.
Si vous passez des handles de fichiers, vous pouvez habituellement
juste utiliser le typeglob tout seul, comme *STDOUT
, mais les
références de typeglobs fonctionnent aussi. Par exemple :
splutter(\*STDOUT); sub splutter { my $fh = shift; print $fh "her um well a hmmm\n"; }
$rec = get_rec(\*STDIN); sub get_rec { my $fh = shift; return scalar <$fh>; }
Si vous comptez générer de nouveau handles de fichiers, vous pourriez faire ceci. Faites attention de renvoyer juste le *FH tout seul, et pas sa référence.
sub openit { my $path = shift; local *FH; return open (FH, $path) ? *FH : undef; }
Perl supporte une sorte de vérification des arguments très limitée lors de la compilation, en utilisant le prototypage de fonction. Si vous déclarez
sub mypush (\@@)
alors mypush()
prendra ses arguments exactement comme push()
le
fait. La declaration de la fonction doit être visible au moment de la
compilation. Le prototype affecte seulement l'interprétation des
appels nouveau style de la fonction, où le nouveau style est défini
comme n'utilisant pas le caractère &
. En d'autres termes, si vous
l'appelez comme une fonction intégrée, alors elle se comportera comme
une fonction intégrée. Si vous l'appelez comme un sous-programme à
l'ancienne mode, alors elle se comportera comme un sous-programme à
l'ancienne. La conséquence naturelle de cette règle est que les
prototypes n'ont pas d'influence sur les références de sous-programmes
comme \&foo
ou sur les appels de sous-programmes indirects comme
&{$subref}
ou $subref->()
.
Les appels de méthode ne sont pas non plus influencés par les prototypes, car la fonction qui doit être appelée est indéterminée au moment de la compilation, puisque le code exact appelé dépend de l'héritage.
Puisque l'intention de cette caractéristique est principalement de vous laisser définir des sous-programmes qui fonctionnent comme des commandes intégrées, voici des prototypes pour quelques autres fonctions qui se compilent presque exactement comme les fonctions intégrées correspondantes.
Déclarées en tant que Appelé comme sub mylink ($$) mylink $old, $new sub myvec ($$$) myvec $var, $offset, 1 sub myindex ($$;$) myindex &getstring, "substr" sub mysyswrite ($$$;$) mysyswrite $buf, 0, length($buf) - $off, $off sub myreverse (@) myreverse $a, $b, $c sub myjoin ($@) myjoin ":", $a, $b, $c sub mypop (\@) mypop @array sub mysplice (\@$$@) mysplice @array, @array, 0, @pushme sub mykeys (\%) mykeys %{$hashref} sub myopen (*;$) myopen HANDLE, $name sub mypipe (**) mypipe READHANDLE, WRITEHANDLE sub mygrep (&@) mygrep { /foo/ } $a, $b, $c sub myrand ($) myrand 42 sub mytime () mytime
Tout caractère de prototype précédé d'une barre oblique inverse
représente un véritable argument qui doit absolument commencer par ce
caractère. La valeur passée comme partie de @_
sera une référence
au véritable argument passé dans l'appel du sous-programme, obtenue en
appliquant \
à cet argument.
Vous pouvez aussi transformer d'un seul coup en référence à plusieurs
types d'argument en utilisant la notation \[]
:
sub myref (\[$@%&*])
qui autorisera les appels suivant à myref() :
myref $var myref @array myref %hash myref &sub myref *glob
et le premier argument de myref()
sera une référence à un scalaire, un
tableau, une table de hachage, du code ou à un glob.
Les caractères de prototype non précédés d'une barre oblique inverse
ont une signification spéciale. Tout @
ou %
sans barre oblique
inverse mange les arguments restants, et force un contexte de
liste. Un argument représenté par $
force un contexte scalaire. Un
&
requiert un sous-programme anonyme, qui, s'il est passé comme
premier argument, ne requiert pas le mot-clé «sub
» ni une virgule
après lui. Un *
permet au sous-programme d'accepter un bareword,
une constante, une expression scalaire, un typeglob, ou une référence
à un typeglob à cet emplacement. La valeur sera disponible pour le
sous-programme soit comme un simple scalaire, soit (dans les deux
derniers cas) comme une référence au typeglob. Si vous désirez
toujours convertir de tels arguments en référence de typeglob,
utilisez Symbol::qualify_to_ref() ainsi :
use Symbol 'qualify_to_ref';
sub foo (*) { my $fh = qualify_to_ref(shift, caller); ... }
Un point-virgule sépare les arguments obligatoires des arguments
optionnels. Il est redondant devant @
ou %
, qui engloutissent
tout le reste.
Notez comment les trois derniers exemples dans la table ci-dessus sont
traités spécialement par l'analyseur. mygrep()
est compilé comme un
véritable opérateur de liste, myrand()
comme un véritable opérateur
unaire avec une précédence unaire identique à celle de rand()
, et
mytime()
est vraiment sans arguments, tout comme
time()
. C'est-à-dire que si vous dites
mytime +2;
Vous obtiendrez mytime() + 2
, et pas mytime(2)
, qui est la façon
dont cela serait analysé sans prototype.
Ce qui est intéressant avec &
est que vous pouvez générer une
nouvelle syntaxe grâce à lui, pourvu qu'il soit en position initiale :
sub try (&@) { my($try,$catch) = @_; eval { &$try }; if ($@) { local $_ = $@; &$catch; } } sub catch (&) { $_[0] }
try { die "phooey"; } catch { /phooey/ and print "unphooey\n"; };
Cela affiche "unphooey"
(Oui, il y a toujours des problèmes non
résolus à propos de la visibilité de @_
. J'ignore cette question
pour le moment (Mais notez que si nous donnons une portée lexicale à
@_
, ces sous-programmes anonymes peuvent agir comme des
fermetures... (Mince, est-ce que ceci sonne un peu lispien ? (Peu
importe))).
Et voici une réimplémentation de l'opérateur grep
de Perl :
sub mygrep (&@) { my $code = shift; my @result; foreach $_ (@_) { push(@result, $_) if &$code; } @result; }
Certaines personnes préféreraient des prototypes pleinement alphanumériques. Les caractères alphanumériques ont intentionnellement été laissés hors des prototypes expressément dans le but d'ajouter un jour futur des paremètres formels nommés. Le principal objectif du mécanisme actuel est de laisser les programmeurs de modules fournir de meilleurs diagnostics à leurs utilisateurs. Larry estime que la notation est bien compréhensible pour les programmeurs Perl, et que cela n'interfèrera pas notablement avec le coeur du module, ni ne le rendra plus difficile à lire. Le bruit sur la ligne est visuellement encapsulé dans une petite pilule facile à avaler.
Si vous essayez d'utiliser des séquences alphanumériques dans un prototype, vous aurez droit à un avertissement optionnel - «Illegal character in prototype...». Malheureusement, les anciennes versions de Perl autorisaient l'utilisation de ce type de prototype tant que le début était un prototype valide. L'avertissement actuel pourrait devenir une erreur fatale dans une future version de Perl lorsque la mejorité du code erroné aura été corrigé.
Il est probablement meilleur de prototyper les nouvelles fonctions, et de ne pas prototyper rétrospectivement les anciennes. C'est parce que vous devez être particulièrement précautionneux avec les exigences silencieuses de la différence entre les contextes de liste et les contextes scalaires. Par exemple, si vous décidez qu'une fonction devrait prendre juste un paramètre, comme ceci :
sub func ($) { my $n = shift; print "you gave me $n\n"; }
et que quelqu'un l'a appelée avec un tableau ou une expression retournant une liste :
func(@foo); func( split /:/ );
Alors vous venez juste de fournir un scalar
automatique devant
leurs arguments, ce qui peut être plus que surprenant. L'ancien
@foo
qui avait l'habitude de ne contenir qu'une chose n'entre plus.
À la place, func()
se voit maintenant passer un 1
; c'est-à-dire
le nombre d'éléments dans @foo
. Et le split
se voit appelé dans
un contexte scalaire et commence à gribouiller dans votre liste de
paramètres @_
. Aïe !
Tout ceci est très puissant, bien sûr, et devrait être utilisé uniquement avec modération pour rendre le monde meilleur.
Les fonctions ayant un prototype égal à ()
sont des candidates
potentielles à l'insertion en ligne (inlining, NDT). Si le résultat
après optimisation et repliement des constantes est soit une constante
soir un scalaire de portée lexicale n'ayant pas d'autre référence,
alors il sera utilisé à la place des appels à la fonction faits sans
&
. Les appels réalisés en utilisant &
ne sont jamais insérés en
ligne (Voir constant.pm pour une façon aisée de déclarer la plupart
des constantes).
Les fonctions suivantes seraient toutes insérées en ligne :
sub pi () { 3.14159 } # Pas exact, mais proche. sub PI () { 4 * atan2 1, 1 } # Aussi exact qu'il # puisse être, et # inséré en ligne aussi !
sub ST_DEV () { 0 } sub ST_INO () { 1 }
sub FLAG_FOO () { 1 << 8 } sub FLAG_BAR () { 1 << 9 } sub FLAG_MASK () { FLAG_FOO | FLAG_BAR }
sub OPT_BAZ () { not (0x1B58 & FLAG_MASK) } sub N () { int(OPT_BAZ) / 3 }
sub FOO_SET () { 1 if FLAG_MASK & FLAG_FOO }
En revanche, celles qui suivent ne pourront être insérées en ligne ; parce qu'elles contiennent des choses non constantes dans leur propre portée.
sub foo_set () { if (FLAG_MASK & FLAG_FOO) { 1 } }
sub baz_val () { if (OPT_BAZ) { return 23; } else { return 42; } }
Si vous redéfinissez un sous-programmes qui pouvait être inséré en
ligne, vous obtiendrez un avertissement formel (vous pouvez utiliser
cet avertissement pour déterminer si un sous-programme particulier est
considéré comme constant ou pas). L'avertissement est considéré comme
suffisamment sévère pour ne pas être optionnel, car les invocations
précédemment compilées de la fonction utiliseront toujours l'ancienne
valeur de cette fonction. Si vous avez besoin de pouvoir redéfinir le
sous-programme, vous devez vous assurer qu'il n'est pas inséré en
ligne, soit en abandonnant le prototype ()
(ce qui change la
sémantique de l'appel, donc prenez garde), soit en contrecarrant le
mécanisme d'insertion d'une autre façon, comme par exemple
sub not_inlined () { 23 if $]; }
Beaucoup de fonctions prédéfinies peuvent être surchargées, même si cela ne devrait être essayé qu'occasionnellement et pour une bonne raison. Typiquement, cela pourrait être réalisé par un paquetage essayant d'émuler une fonctionnalité prédéfinie manquante sur un système non Unix.
La surcharge ne peut être réalisée qu'en important le nom depuis un
module lors de la compilation -- la prédéclaration ordinaire n'est pas
suffisante. Toutefois, le pragma use subs
vous laisse, dans les
faits, prédéclarer les sous-programmes via la syntaxe d'importation,
et ces noms peuvent ensuite surcharger ceux qui sont prédéfinis :
use subs 'chdir', 'chroot', 'chmod', 'chown'; chdir $somewhere; sub chdir { ... }
Pour se référer sans ambiguïté à la forme prédéfinie, on peut faire
précéder le nom prédéfini par le qualificateur de paquetage spéciale
CORE::
. Par exemple, le fait de dire CORE::open()
se réfère
toujours à la fonction prédéfinie open()
, même si le paquetage
courant a importé d'ailleurs un quelconque autre sous-programme appelé
&open()
. Même si cela a l'air d'un appel de fonction normal, ce
n'en est pas un : vous ne pouvez pas en créer de référence, telle que
celles que l'incorrect \&CORE::open
pourrait en produire.
Les modules de bibliothèque ne devraient en général pas exporter de
noms prédéfinis comme open
ou chdir
comme partie de leur liste
@EXPORT
par défaut, car ceux-ci pourraient s'infiltrer dans
l'espace de noms de quelqu'un d'autre et changer la sémantique de
façon inattendue. À la place, si le module ajoute ce nom à
@EXPORT_OK
, alors il est possible pour un utilisateur d'importer le
nom explicitement, mais pas implicitement. C'est-à-dire qu'il pourrait
dire
use Module 'open';
et cela importerait la surcharge open
. Mais s'il disait
use Module;
il obtiendrait les importations par défaut sans les surcharges.
Le mécanisme précédent de surcharge des éléments prédéfinis est
restreint, assez délibérément, au paquetage qui réclame l'importation.
Il existe une seconde méthode parfois applicable lorsque vous désirez
surcharger partout une fonction prédéfinie, sans tenir compte des
frontières entre espaces de noms. Cela s'obtient en important un
sous-programme dans l'espace de noms spécial CORE::GLOBAL::
. Voici
un exemple qui remplace assez effrontément l'opérateur glob
par
quelque chose qui comprend les expressions rationnelles.
package REGlob; require Exporter; @ISA = 'Exporter'; @EXPORT_OK = 'glob';
sub import { my $pkg = shift; return unless @_; my $sym = shift; my $where = ($sym =~ s/^GLOBAL_// ? 'CORE::GLOBAL' : caller(0)); $pkg->export($where, $sym, @_); }
sub glob { my $pat = shift; my @got; local *D; if (opendir D, '.') { @got = grep /$pat/, readdir D; closedir D; } return @got; } 1;
Et voici comment on pourrait en (ab)user :
#use REGlob 'GLOBAL_glob'; # surcharge glob() dans TOUS les # espaces de noms package Foo; use REGlob 'glob'; # surcharge glob() dans Foo:: # seulement print for <^[a-z_]+\.pm\$>; # montre tous les modules pragmatiques
Le commentaire initial montre un exemple artificiel, voire même
dangereux. En surchargeant glob
globalement, vous forceriez le
nouveau (et subversif) comportement de l'opérateur glob
pour
tous les espaces de noms, sans la complète coopération des modules
qui possèdent ces espaces de noms, et sans qu'ils en aient même
connaissance. Naturellement, ceci doit être fait avec d'extrêmes
précautions -- si jamais cela doit être fait.
L'exemple REGlob
ci-dessus n'implémente pas tous le support
nécessaires pour surcharger proprement l'opérateur glob
de perl. La
fonction intégrée glob
a des comportements différents selon qu'elle
apparaît dans un contexte scalaire ou un contexte de lites, mais ce
n'est pas le cas de notre REGlob
. En fait, beaucoup de fonctions
prédéfinies de perl ont de tels comportements sensibles au contexte,
et ceux-ci doivent être supportés de façon adéquate par une surcharge
correctement écrite. Pour un exemple pleinement fonctionnel de
surcharge de glob
, étudiez l'implémentation de File::DosGlob
dans la bibliothèque standard.
Lorsque vous surchargez une fonction prédéfinie, votre surcharge
devrait être cohérente (si possible) avec la syntaxe native de
l'originale. Vous pouvez le faire en utilisant le prototype
approprié. Pour obtenir le prototype d'une fonction prédéfinie
surchargeable, utilisez la fonction prototype
avec comme argument
"CORE::nom_de_la_fonction"
(voir prototype dans la page de manuel perlfunc).
Remarquez que certaines fonctions prédéfinies utilise une syntaxe non
représentable par un prototype (par exemple system
ou chomp
). Si
vous les surchargez, vous ne pourrez pas simuler leur syntaxe
d'origine.
Les «fonctions» prédéfinies do
, require
et glob
peuvent
elles-aussi être surchargées, mais comme elles sont magiques, elles
conservent leur syntaxe d'origine et vous n'avez pas besoin de définir
de prototype pour leurs fonctions de remplacement. (Par contre, vous
ne pouvez pas surcharger la syntaxe do BLOC
).
require
possède en plus un peu de magie noire ; si vous appelez
votre fonction require
de remplacement par require Foo::Bar
,
vous recevrez en fait l'argument "Foo/Bar.pm"
dans @_. Voir
require dans la page de manuel perlfunc.
Et, en se référant à l'exemple précédent, si vous surchargez glob
,
l'opérateur «glob» <<*>
sera aussi surchargé.
De manières similaire, la surcharge de la fonction readline
surcharge aussi l'opérateur d'E/S équivalent <FILEHANDLE>
.
Et pour finir, certaines fonctions prédéfinies (comme exists
ou
grep
) ne peuvent pas être surchargées.
Si vous appelez un sous-programme qui n'est pas défini, vous obtenez
ordinairement une erreur fatale immédiate se plaignant que le
sous-programme n'existe pas (De même pour les sous-programmes utilisés
comme méthodes, lorsque la méthode n'existe dans aucune classe de base
du paquetage de la classe). Toutefois, si un sous-programme
AUTOLOAD
est défini dans le paquetage ou dans les paquetages
utilisés pour localiser le sous-programme originel, alors ce
sous-programme AUTOLOAD
est appelé avec les arguments qui auraient
été passés au sous-programme originel. Le nom pleinement qualifié du
sous-programme originel apparaît magiquement dans la variable globale
$AUTOLOAD du même paquetage que la routine AUTOLOAD
. Le nom n'est
pas passé comme un argument ordinaire parce que, euh, eh bien, juste
parce que, c'est pour ça...
La plupart des routines AUTOLOAD
chargent une définition du
sous-programme requis en utilisant eval(), puis l'exécutent en
utilisant une forme spéciale de goto()
qui efface la routine
AUTOLOAD
de la pile sans laisser de traces (Voir le module standard
AutoLoader
pour un exemple). Mais une routine AUTOLOAD
peut
aussi juste émuler la routine et ne jamais la définir. Par exemple,
supposons qu'une fonction non encore définie doive juste appeler
system
avec ces arguments. Tout ce que vous feriez est ceci :
sub AUTOLOAD { my $program = $AUTOLOAD; $program =~ s/.*:://; system($program, @_); } date(); who('am', 'i'); ls('-l');
En fait, si vous prédéclarez les fonctions que vous désirez appeler de cette façon, vous n'avez mêmes pas besoin des parenthèses :
use subs qw(date who ls); date; who "am", "i"; ls -l;
Un exemple plus complet de ceci est le module Shell standard, qui peut traiter des appels indéfinis à des sous-programmes comme des appels de programmes externes.
Des mécanismes sont disponibles pour aider les auteurs de modules à découper les modules en fichiers autochargeables. Voir le module standard AutoLoader décrit dans AutoLoader et dans AutoSplit, les modules standards SelfLoader dans SelfLoader, et le document expliquant comment ajouter des fonctions C au code Perl dans la page de manuel perlxs.
Une déclaration ou une définition de sous-programme peut contenir une
liste d'attributs qui lui sont associés. Si une telle liste est
présente, elle est découpée aux espaces et aux deux-points et traitée
comme si un use attributes
avait été rencontré. Voir attributes
pour plus de détails sur les différents attributs actuellement
supportés. Contrairement aux limitations de l'use attrs
obsolète,
la syntaxe sub : ATTRLIST
fonctionne pour associer les attributs à
une prédéclaration, et pas seulement dans la définition de
sous-programme.
Les attributs doivent être des identifiants simples valides (sans aucune ponctuation à part le caractère «_»). Ils peuvent être suivis d'une liste de paramètres, qui n'est contrôlée que pour voir si ses parenthèses ('(',')') sont correctement imbriquées.
Exemples de syntaxe valide (même si les attributs sont inconnus) :
sub fnord (&\%) : switch(10,foo(7,3)) : expensive ; sub plugh () : Ugly('\(") :Bad ; sub xyzzy : _5x5 { ... }
Exemples de syntaxe invalide :
sub fnord : switch(10,foo() ; # () non équilibrées sub snoid : Ugly('(') ; # () non équilibrées sub xyzzy : 5x5 ; # "5x5" n'est pas un identifiant valide sub plugh : Y2::north ; # "Y2::north" n'est pas un identifiant simple sub snurt : foo + bar ; # "+" n'est pas un deux-points ni une espace
La liste d'attributs est passée comme une liste de chaînes constantes au code qui les associe au sous-programme. En particulier, le second exemple de syntaxe valide ci-dessus à cette allure en termes d'analyse syntaxique et d'invocation :
use attributes __PACKAGE__, \&plugh, q[Ugly('\(")], 'Bad';
Pour plus de détails sur les listes d'attributs et leur manipulation, voir attributes en la page de manuel Attributes::Handlers.
Voir Modèles de fonctions dans la page de manuel perlref pour plus de détails sur les références et les fermetures. Voir la page de manuel perlxs pour apprendre à appeler des sous-programmes en C depuis Perl. Voir la page de manuel perlembed pour apprendre à appeler des sous-programmes Perl depuis C. Voir la page de manuel perlmod pour apprendre à emballer vos fonctions dans des fichiers séparés. Voir la page de manuel perlmodlib pour apprendre quels modules de bibliothèques sont fournis en standard sur votre système. Voir la page de manuel perltoot pour apprendre à faire des appels à des méthodes objet.
Cette traduction française correspond à la version anglaise distribuée avec perl 5.8.8. Pour en savoir plus concernant ces traductions, consultez http://perl.enstimac.fr/.
Traduction : Roland Trique <roland.trique@free.fr>. Mise à jour : Paul Gaborit <paul.gaborit at enstimac.fr>.
Personne pour l'instant.
perlsub - Les sous-programmes de Perl |