Cours gratuits » Cours informatique » Cours programmation » Cours Perl » Cours Perl pas a pas : operateurs, structures de controle et fonctions

Cours Perl pas a pas : operateurs, structures de controle et fonctions

Problème à signaler:

Télécharger



★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Cours Perl pas à pas : opérateurs, structures de contrôle et fonctions

Perl est l’abréviation de “Practical Extraction and Report Language” (un langage adapté à l’extraction et la génération de rapports). Il a été développé durant les années 80 par Larry Wall. C’est un langage interprété dont la syntaxe est proche des scripts shell, awk, sed ou encore de celle du langage C.

Un langage très puissant

  • Programmations impérative, fonctionnelle et orientée objet,
  • R&eacu
te;cursivité, modularité, exceptions,
  • Tableaux, listes et tables de hachage (tableaux associatifs) natifs,
  • Gestion mémoire : ramasse-miettes,
  • Expressions régulières,
  • Richesse des bibliothèques (e?cacité de programmation),
  • Multi plateforme (87 portages),
  • Apprentissage facilité (C, sh, sed, POSIX, ),
  • Débuggeur intégré.
  • Passage des paramètres

    • Les paramètres d’un sous-programme constituent un tableau noté @ . Ses éléments sont $ [0], $ [1],$ [$# ].
    • Les paramètres sont passés par valeur.
    • On peut passer des paramètres par référence pour modi?er leurs valeurs.

    Valeur de retour

    Un sous-programme renvoie une valeur ou un tableau de valeurs.

    S’il n’y a pas dereturn la valeur de la dernière expression est renvoyée.

    On peut renvoyer des références pour des structures plus complexes.

    Module

    Constructeurs et Destructeurs de paquetage :

    BEGIN { } bloc exécuté dès que possible

    END { } bloc exécuté aussi tard que possible

    Module :

    Un module est un paquetage défini dans un fichier de même nom et l’extension.pm destiné à être réutilisé.

    La programmation objet en Perl

    Classe :

    Une classe est un module qui fournit les sous-programmes qui peuvent être utilisés comme méthodes.

    Méthode :

    Une méthode est juste un sous-programme qui prévoit que son premier argument est le nom d’un module ou une référence.

    Expression régulière

    Une expression régulière ou rationnelle est un masque sous forme de suite de caractères qui permet de décrire le contenu d’une chaîne de caractères, afin de tester si cette dernière correspond à un motif, d’en extraire des informations ou bien d’y effectuer des substitutions.

    Syntaxe héritée d’Unix, semblable à la base à celle de la commande grep

    Fonctionnalités supplémentaires

    Pratique pour analyser des fichiers texte

    Pratique pour contrôler les entrées des scripts CGI

    Tutoriels accessibles avec man, perl requick et perl retut

    La reconnaissance de motif ou pattern matching

    L’opérateur m/MOTIF/cgimosx ou/MOTIF/cgimosx :

    Lorsque/ est utilisé comme délimiteur,m est otpionnel.

    Lorsque m est utilisé, on peut utiliser n’importe quelle paire de caractères ni alphanumériques ni blancs comme délimiteurs.

    Les modificateurs :

    c ne pas réinitialiser la position de recherche lors d’un échec avec/g

    g recherche globale, trouver toutes les occurrences

    i reconnaissance de motif indépendamment de la casse (maj/min)

    m traitement de chaîne comme étant multi-lignes

    o compilation du motif uniquement la première fois

    s traitement de la chaîne comme étant une seule ligne

    x utilisation des expressions rationnelles étendues 

    ...

    Le concept de fermeture provient de la programmation fonctionnelle et, à ceux qui sont résolument attachés à la programmation procédurale ou à la programmation orientée objet, l’objet caché derrière une référence à du code doit vraisemblablement resté mys¬térieux. L’objet créé et retourné par la méthode new() n’est plus une référence vers des données comme nous l’avons vu auparavant. C’est une référence à du code anonyme qui a accès à sa propre version des données de l’objet (liaison lexicale et instanciation) qui est stockée dans la variable privée $self. Bien que ce soit la même fonction (NDT: le même code) à chaque fois, il contient une version différente de $self.

    Quand une méthode comme $him->name("Jason") est appelée, son "zéroième" argument implicite est l’objet appelant – exac¬tement comme pour tous les appels de méthodes. Mais dans notre cas, c’est une référence à notre code (quelque chose comme un pointeur sur fonction en C++ mais avec une liaison vers des variables lexicales). À part l’appeler, on ne peut pas faire grand chose d’une référence vers du code. C’est donc exactement ce que nous faisons en disant &{$_[0]}. C’est juste un appel à une fonction et non pas un appel de méthode. Le premier argument est le chaîne "NAME" et tous les autres arguments sont ceux qui ont été passés à la méthode.

    Une fois en cours d’exécution de la fermeture créée par new(), la référence $self à la table de hachage devient soudainement visible. La fermeture retrouve son premier argument ("NAME" dans ce cas puisque c’est ce que lui passe la méthode name()) et l’utilise comme clé d’accès à cette table de hachage privée qui est cachée dans sa propre version de $self.

    Rien ne permet à quiconque d’accéder à ces données cachées en dehors de l’exécution de cette méthode. Ou presque rien : vous pourriez utiliser le deboggueur en allant pas à pas jusque dans le code de la méthode et voir les données mais en dehors de cela aucune chance d’y accéder.

    Bon, si tout ça n’intéresse pas les adeptes de Scheme alors je ne vois ce qui pourrait les intéresser. La transposition de ces techniques en C++, Java ou tout autre langage de conception statique est laissé comme exercice futile à leurs aficionados.

    Via la fonction caller(), vous pouvez même ajouter un peu plus de confidentialité en contraignant la fermeture à n’accepter que les appels provenant de son propre paquetage. Cela devrait sans aucun doute satisfaire les plus exigeants...

    Vous avez eu ici de quoi satisfaire votre orgueil (la troisième vertu principale du programmeur). Plus sérieusement, l’orgueil est tout simplement la fierté de l’artisan qui vient d’écrire un bout de code bien conçu.

    AUTOLOAD: les méthodes proxy

    l’auto-chargement (ou autoload) est un moyen d’intercepter l’appel à une méthode non définie. Une subroutine d’auto-chargement peux soit créer une nouvelle fonction au vol, soit en charger une depuis le disque, soit l’évaluer elle-même. Cette stratégie de définition au vol est ce qu’on appelle auto-chargement.

    Mais ce n’est qu’une approche possible. Dans une autre approche, c’est la méthode d’auto-chargement qui fournit elle-même le ser¬vice demandée. Utilisée de cette manière, on peut alors considérer cette méthode d’auto-chargement comme des méthodes "proxy".

    Quand Perl essaie d’appeler une fonction non définie dans un paquetage particulier et que cette fonction n’est pas définie, il cherche alors dans le même paquetage une fonction appelé AUTOLOAD. Si elle existe, elle est appelée avec les mêmes arguments que la fonction originale. Le nom complet de la fonction dans la variable $AUTOLOAD du paquetage. Une fois appelée, la fonction peut faire tout ce qu’elle veut et, entre autres, définir une nouvelle fonction avec le bon nom puis faire une sorte de goto vers elle en s’effaçant de la pile d’appel.

    Quel rapport avec les objets? Après tout, nous ne parlons que de fonctions, pas de méthodes. En fait, puisqu’une méthode n’est qu’une fonction avec un argument supplémentaire et quelques sémantiques sympathiques permettant de la retrouver, nous pouvons aussi utiliser l’auto-chargement pour les méthodes. Perl ne commence la recherche de méthodes par auto-chargement que lorsqu’il a fini l’exploration via @ISA. Certains programmeurs ont même défini une méthode UNIVERSAL::AUTOLOAD pour intercepter tous les appels à des méthodes non définies pour n’importe quelle sorte d’objets.

    Méthodes auto-chargée d’accès aux données

    Vous êtes peut-être resté un peu sceptique devant la duplication de code que nous avons exposé tout d’abord dans la classe Per-son puis dans la classe Employee. Chaque méthode d’accès aux données de la table de hachage est virtuellement identique. Cela devrait chatouiller votre plus grande vertu de programmeur: l’impatience. Mais votre paresse l’a emporté et vous n’avez rien fait. Heureusement, les méthodes proxy sont le remède à ce problème.

    Au lieu d’écrire une nouvelle fonction à chaque fois que nous avons besoin d’un nouveau champ, nous allons utiliser le mécanisme d’auto-chargement pour générer (en fait, simuler) les méthodes au vol. Pour vérifier que nous accédons à un membre valide, nous le rechercherons dans le champ _permitted (qui, en anglais, se prononce "under-permitted"). Ce champ est une référence à une table de hachage de portée lexicale limitée au fichier (comme une variable C statique d’un fichier) contenant les champs autorisés et appelée %fields. Pourquoi le caractère de soulignement? Pour le même raison que celui de _CENSUS : c’est un indicateur qui signifie "à usage interne seulement".

    Voici à quoi ressemblent le code d’initialisation et le constructeur de la classe si nous suivons cette approche :

    package Person; use Carp;

    use vars qw($AUTOLOAD); # it’s a package global

    my %fields = (

    name   => undef,

    age      => undef,

    peers   => undef,

    );

    sub new {

    my $that = shift;

    my $class = ref($that) || $that;

    my $self = {

    _permitted => \%fields,

    %fields,

    };

    bless $self, $class;

    return $self;

    }

    Si nous voulons spécifier des valeurs par défaut pour nos champs, nous pouvons remplacer les undef dans la table de hachage %fields.

    Avez-vous remarqué comment nous stockons la référence à nos données de classe dans l’objet lui-même? Souvenez-vous qu’il est fondamental d’accéder aux données de classe à travers l’objet lui-même plutôt que d’utiliser directement %fields dans les méthodes. Sinon vous ne pourrez pas convenablement hériter.

    La vraie magie réside dans notre méthode proxy qui gérera tous les appels à des méthodes non définies pour des objets de la classe Person (ou des sous-classes de Person). Elle doit s’appeler AUTOLOAD. Encore une fois, son nom est tout en majuscule parce qu’elle est implicitement appelée par Perl et non pas directement par l’utilisateur.

    sub AUTOLOAD {

    my $self = shift;

    my $type = ref($self)

    or croak "$self is not an object";

    my $name = $AUTOLOAD;

    $name =~ s/.*://;        # strip fully-qualified portion

    unless (exists $self->{_permitted}->{$name} ) {

    croak "Can’t access ‘$name’ field in class $type";

    }

    if (@_) {

    return $self->{$name} = shift;

    } else {

    return $self->{$name};

    }

    }

    Assez chouette, non? La seule chose à faire pour ajouter de nouveaux champs est de modifier %fields. Il n’y a aucune nouvelles fonctions à écrire.

    J’aurais même pu supprimer complètement le champ _permitted mais je voulais illustrer comment stocker une référence à une donnée de classe dans un objet de manière à ne pas accéder à cette donnée directement dans les méthodes.

    Méthodes d’accès aux données auto-chargées et héritées

    Qu’en est-il de l’héritage ? Pouvons-nous définir la classe Employee de la même manière ? Oui, si nous faisons un peu attention. Voici comment faire:

    package Employee; use Person;

    use strict;

    use vars qw(@ISA); @ISA = qw(Person);

    my %fields = (

    id         => undef,

    salary  => undef,

    );

    sub new {

    my $that = shift;

    my $class = ref($that) || $that;

    my $self = bless $that->SUPER::new(), $class;

    my($element);

    foreach $element (keys %fields) {

    $self->{_permitted}->{$element} = $fields{$element};

    }

    @{$self}{keys %fields} = values %fields;

    return $self;

    }

    Une fois cela fait, nous n’avons même pas à définir une fonction AUTOLOAD dans le paquetage Employee puisque la version fournie par Person via l’héritage fonctionne très bien.

    17.8 Méta-outils classiques

    Même si l’approche par les méthodes proxy est plus pratique pour fabriquer des classes ressemblant à des structures que l’approche fastidieuse nécessitant le codage de chacune des fonctions d’accès, elle laisse encore un peu à désirer. Par exemple, vous devez gérer les appels erronés que vous ne voulez pas capter via votre proxy. Il faut aussi faire attention lors de l’héritage comme nous l’avons montré précédemment.

    Les programmeurs Perl ont répondu aux besoins en créant différentes classes de construction de classes. Ces méta-classes sont des classes qui créent d’autres classes. Deux d’entre elles méritent notre attention : Classs::Struct et Alias. Celles-ci ainsi que d’autres classes apparentées peuvent être récupérées dans le répertoire modules du CPAN.

    Class::Struct

    La plus vieille de toutes est Class::Struct. En fait, sa syntaxe et son interface étaient esquissées alors même que perl5 n’existait pas encore. Elle fournit le moyen de "déclarer" une classe d’objets dont le type de chaque champ est spécifié. La fonction permettant de faire cela s’appelle (rien de surprenant) struct(). Puisque les structures ou les enregistrements ne sont pas des types de base de Perl, à chaque fois que vous voulez créer une classe pour fournir un objet de type structure, vous devez vous-mêmes définir la méthode new() ainsi que les méthodes d’accès aux données pour chacun des champs. Très rapidement, vous trouverez cela enquiquinant (pour ne pas dire autre chose). La fonction Class::Struct::struct() vous soulagera de cette tâche ennuyeuse.

    Voici un simple exemple d’utilisation :

    use Class::Struct qw(struct);

    use Jobbie; # défini par l’utilisateur; voir plus bas

    struct ’Fred’ => {

    one      => ’$’,

    many   => ’@’,

    profession => Jobbie, # appel de Jobbie->new()

    };

    $ob = Fred->new; $ob->one("hmmmm");

    $ob->many(0, "here");

    $ob->many(1, "you");

    $ob->many(2, "go");

    print "Just set: ", $ob->many(2), "\n";

    $ob->profession->salary(10_000);

    Les types des champs dans la structure peuvent être déclarés comme des types de base de Perl ou comme des types utilisateurs (classes). Les types utilisateurs seront initialisés par l’appel de la méthode new() de la classe.

    Voici un exemple réel d’utilisation de la génération de structure. Supposons que vous vouliez modifier le fonctionnement des fonc¬tions Perl gethostbyname() et gethostbyaddr() pour qu’elles renvoient des objets qui fonctionnent comme des structures C. Nous ne voulons pas d’OO, ici. La seule chose que nous voulons c’est que ces objets se comporte comme des structures au sens C du terme.

    use Socket;

    use Net::hostent;

    $h = gethostbyname("perl.com"); # object return printf "perl.com’s real name is %s, address %s\n", $h->name, inet_ntoa($h->addr);

    Voici comment faire en utilisant le module Class::Struct. Le point crucial est cet appel :

    struct ’Net::hostent’ =>           [           # notez le crochet

    name   =>       ’$’,

    aliases =>       ’@’,

    addrtype         =>       ’$’,

    ’length’ =>       ’$’,

    addr_list          =>       ’@’,

    ];

    qui crée les méthodes d’objets avec les bons noms et types. Il crée mêm

    ...

    Outre la création dynamique de classes, nous n’avons qu’effleuré certains concepts comme la redéfinition des fonctions de base, l’import/export de bits, le prototypage de fonctions, les raccourcis d’appels de fonctions via &whatever et le remplacement de fonction par goto &whatever. Ils ont tous un sens du point de vue des modules traditionnels mais, comme vous avez pu le constater, vous pouvez aussi les utiliser dans un module objet.

    Dans la version 5.004 de Perl, vous pouvez trouver d’autres modules objet qui redéfinissent les fonctions de base avec des structures: File::stat, Net::hostent, Net::netent, Net::protoent, Net::servent, Time::gmtime, Time::localtime, User::grent et User::pwent. Le com¬posant final du nom de tous ces modules est entièrement en minuscules qui, par convention, sont réservés aux pragma du compilateur parce qu’ils modifient la compilation et les fonctions internes. Ils proposent en outre les noms de type qu’un programmeur C attend.

    Les données membres comme des variables

    Si vous utilisez des objets C++ vous êtes habitué à accéder aux données membres d’un objet par simples variables lorsque vous êtes dans une méthode. Le module Alias offre entre autres cette fonctionnalité ainsi que la possibilité d’avoir des méthodes privées que les objets peuvent appeler mais qui ne peuvent l’être depuis l’extérieur de la classe.

    Voici un exemple de classe Person créée en utilisant le module Alias. Quand vous mettez à jour ces instances des variables, vous mettez à jour automagiquement les champs correspondants de la table de hachage. Pratique, non?

    package Person;

    # C’est la même chose qu’avant...

    sub new {

    my $that = shift;

    my $class = ref($that) || $that;

    my $self = {

    NAME => undef,

    AGE => undef,

    PEERS => [],

    };

    bless($self, $class);

    return $self;

    }

    use Alias qw(attr);

    use vars qw($NAME $AGE $PEERS);

    sub name {

    my $self = attr shift; if (@_) { $NAME = shift; }

    return  $NAME;

    }

    sub age {

    my $self = attr shift; if (@_) { $AGE = shift; }

    return  $AGE;

    }

    sub peers {

    my $self = attr shift; if (@_) { @PEERS = @_; }

    return  @PEERS;

    }

    sub exclaim {

    my $self = attr shift;

    return sprintf "Hi, I’m %s, age %d, working with %s",

    $NAME, $AGE, join(", ", @PEERS);

    }

    sub happy_birthday { my $self = attr shift;

    return ++$AGE;

    }

    La déclaration use vars est nécessaire parce que le module Alias bidouille les variables globales du paquetage qui ont le même nom que les champs. Pour pouvoir utiliser des variables globales avec use strict, vous devez les déclarer au préalable. Ces variables globales du paquetage sont localisées dans le bloc englobant l’appel à attr() exactement comme si vous aviez utilisé local(). Par contre, cela signifie qu’elles sont considérées comme des variables globales avec des valeurs temporaires comme avec tout autre local().

    Il serait joli de combiner Alias avec quelque chose comme Class::Struct ou Class::MethodMaker.

    NOTES

    Terminologie objet

    Dans la littérature OO, un grand nombre de mots différents sont utilisés pour nommer quelques concepts. Si vous n’êtes pas déjà un programmeur objet vous n’avez pas à vous en préoccuper. Dans le cas contraire, vous aimeriez sûrement savoir à quoi correspondent ces concepts en Perl.

    Par exemple, un objet est souvent appelé une instance d’une classe et les méthodes objet méthodes d’instance. Les champs spécifiques de chaque objet sont souvent appelés données d’instance ou attributs d’objet. Tandis que les champs communs à tous les membres de la classe sont nommés donnée de classe, attributs de classe ou <données membres statiques>.

    classe de base, classe générique et super classe recouvrent tous la même notion. classe dérivée, classe spécifzque et sous-classe décrivent aussi la même chose.

    Les programmeurs C++ ont des méthodes statiques et des méthodes virtuelles mais Perl ne propose que les méthodes de classe et les méthodes d’objet. En fait, Perl n’a que des méthodes. Qu’une méthode s’applique à une classe ou à un objet ne se fait qu’à l’usage. Vous pouvez accidentellement appeler une méthode de classe (une méthode qui attend une chaîne comme argument implicite) comme une méthode d’objet (une méthode qui attend une référence comme argument implicite) ou vice-versa.

    Du point de vue C++, toutes les méthodes en Perl sont virtuelles. C’est pourquoi il n’y a jamais de vérification des arguments par rapport aux prototypes des fonctions comme cela peur se faire pour les fonctions prédéfinies ou définies par l’utilisateur.

    Puisque une classe... (NDT: je n’ai pas compris ce paragraphe!) Because a class is itself something of an object, Perl’s classes can be taken as describing both a "class as meta-object" (also called objectfactory) philosophy and the "class as type definition" (declaring behaviour, not defzning mechanism) idea. C++ supports the latter notion, but not the former.

    Objets de Perl

    DESCRIPTION

    Tout d’abord, vous devez comprendre ce que sont les références en Perl. Voir le manuel perlref pour cela. Ensuite, si vous trouvez encore le travail qui suit sur les références trop compliqué, un tutoriél sur la programmation orientée objet en Perl se trouve dans le manuel perltoot.

    Si vous êtes toujours avec nous, alors voici trois définitions très simples que vous devriez trouver rassurantes.

    Un objet est simplement une référence qui s’avère savoir à quelle classe elle appartient.

    Une classe est simplement un paquetage qui fournit des méthodes pour manipuler les références d’ojet.

    Une méthode est simplement un sous-programme qui attend une référence d’objet (ou un nom de paquetage, pour les méthodes de classe) comme premier argument.

    Nous allons maintenant couvrir ces points plus en détails.

    Un Objet est Simplement une Référence

    Contrairement, disons, à C++, Perl ne fournit aucune syntaxe particulière pour les constructeurs. Un constructeur est juste un sous-programme qui retourne une référence à quelque chose qui a été "consacré" pour devenir une classe, généralement la classe dans laquelle le sous-programme est défini. Voici un constructeur typique:

    package Critter; sub new { bless {} }

    Ce mot-clé new n’a rien de spécial. Vous auriez aussi pu écrire un constructeur de cette façon:

    package Critter;

    sub spawn { bless {} }

    En fait, ceci pourrait même être préférable, car les programmeurs C++ n’auront pas tendance à penser que new fonctionne en Perl de la même manière qu’en C++. Car ce n’est pas le cas. Nous vous recommandons de nommer vos constructeurs de façon qu’ils aient un sens en fonction du contexte du problème que vous résolvez. Par exemple, les constructeurs dans l’extension Tk de Perl portent les noms des widgets qu’ils créent.

    Une différence entre les constructeurs de Perl et de C++ est qu’en Perl, ils doivent allouer leur propre mémoire (L’autre différence est qu’ils n’appellent pas automatiquement les constructeurs de classe de base surchargés). Le {} alloue un hachage anonyme ne contenant aucune paire clé/valeur, et le retourne. Le bless() prend cette référence et dit à l’objet qu’il référence qu’il est désormais un Critter, et retourne la référence. C’est pour que cela soit plus pratique, car l’objet référencé sait lui-même qu’il a été consacré, et sa référence aurait pu être retournée directement, comme ceci :

    sub new {

    my $self = {}; bless $self; return $self;

    }

    En fait, vous voyez souvent de telles choses dans des constructeurs plus compliqués qui veulent utiliser des méthodes de la classe pour sa construction :

    sub new {

    my $self = {}; bless $self;

    $self->initialize();

    return $self;

    }

    si vous vous souciez de l’héritage (et vous devriez; voir le titre Modules: Création, Usage, et Abus dans le manuel perlmodlib), alors vous préférerez utiliser la forme à deux arguments de bless pour que vos constructeurs puissent être hérités :

    sub new {

    my $class = shift; my $self = {};

    bless $self, $class; $self->initialize(); return $self;

    }

    Ou si vous vous attendez à ce que les gens appellent non pas seulement CLASS->new() mais aussi $obj->new(), alors utilisez quelque chose comme ceci. La méthode initialize() sera celle de la classe dans laquelle nous consacrons l’objet :

    sub new {

    my $this = shift;

    my $class = ref($this) || $this;

    my $self = {};

    bless $self, $class;

    $self->initialize();

    return $self;

    }

    À l’intérieur du paquetage de la classe, les méthodes gèreront habituellement la référence comme une référence ordinaire. À l’ex-térieur du paquetage, la référence est généralement traitée comme une valeur opaque à laquelle on ne peut accéder qu’à travers les méthodes de la classe.

    Un constructeur peut re-consacrer un objet référencé appartenant couramment à une autre classe, mais alors la nouvelle classe est responsable de tout le nettoyage par la suite. Le sacrement précédent est oublié, puisqu’un objet ne peut appartenir qu’à une seule classe à un moment donné (même si bien sûr il est libre d’hériter de méthodes provenant de plusieurs classes). Si toutefois vous vous retrouvez dans l’obligation de faire ceci, la classe mère ne se comporte alors probablement pas correctement.

    Une clarification: les objets de Perl sont consacrés. Les références ne le sont pas. Les objets savent à quel paquetage ils appartiennent. Pas les références. La fonction bless() utilise la référence pour trouver l’objet. Considérez l’exemple suivant :

    $a = {};

    $b = $a;

    bless $a, BLAH;

    print "\$b is a ", ref($b), "\n";


    43