• 1.1 Présentation du langage
  • 1.1.1 Note sur Perl6
  • 1.2 Installation sous Unix/Linux et Windows
  • 1.2.1 Pour Unix et Linux
  • 1.2.2 Pour Windows
  • 1.3 Aides en ligne : les indispensables
  • 2.1 Algorithmes
  • 2.2 Structures du langage Perl
  • 2.2.1 déclaration et portée lexicale
  • 2.3 Les scalaires
  • 2.4 Gestion des opérateurs sur scalaires
  • 2.4.1 fonctions chop et chomp
  • 2.4.2 sortie écran STDOUT
  • 2.4.3 impression
  • 2.5 Les listes et tableaux
  • 2.6 Les tests
  • 2.6.1 Tests simples
  • 2.6.2 Les tests séquentiels
  • 2.7 Les boucles : définies et indéfinies
  • 2.7.1 Structures de boucles
  • 2.7.2 Les instructions de contrôle des boucles
  • 2.8 Les instructions de branchement
  • 2.8.1 L'instruction goto
  • 2.9 Les instructions abrégées
  • 2.10 Les tableaux associatifs ou hachage
  • 2.11 Gestion des fichiers et des répertoires
  • 2.11.1 Les entrées/sorties : saisie
  • 2.12 Traitement sur les fichiers : lecture, écriture, informations.
  • 2.12.1 Ouverture en lecture
  • 2.12.2 Ouverture en écriture
  • 2.12.3 Répertoires
  • 2.13 Les références : sur tableaux et anonymes
  • 2.13.1 Documents Perl relatifs aux références
  • 3.1 Scalaires prédéfinis
  • 3.2 Liste et hashs prédéfinis
  • 4.1 Description
  • 4.1.1 documentation perl à consulter
  • 4.1.2 Note
  • 4.2 Symboles élémentaires
  • 4.3 Symboles de répétitions
  • 4.4 Les motifs
  • 4.5 substitution
  • 4.6 Les modificateurs
  • 4.6.1 Les regroupements
  • 4.6.2 Variables prédéfinies pour les expressions rationnelles.
  • 4.7 fonctions split et join
  • 4.7.1 documentation Perl à consulter
  • 4.7.2 La fonction split
  • 4.7.3 La fonction join
  • 4.8 Utilisation interactive de l'interpréteur Perl
  • 4.8.1 Pas vraiment de mode interactif
  • 4.8.2 Débogage
  • 5.1 Présentation
  • 5.2 Paramètres, visibilité et retour
  • 5.2.1 paramètres
  • 5.2.2 visibilité
  • 5.2.3 retour
  • 5.3 Notion de variables semis-privées
  • 5.4 Retour scalaire ou liste selon contexte
  • 5.5 Utilisation de références dans les arguments
  • 5.6 Les références sur fonctions
  • 5.6.1 références sur une sub nommée
  • 5.6.2 références sur sub anonyme
  • 6.1 Les fonctions intégrées et modules
  • 6.1.1 Simple collection de routines
  • 6.2 Utilisation d'un module non orienté objet
  • 6.2.1 notion de package
  • 6.2.2 L'instruction use
  • 6.3 Utilisation d'un module orienté objet
  • 6.3.1 Notion d'objet
  • 6.3.2 Mise en oeuvre d'un module objet simple
  • 6.3.3 Conclusion
  • 7.1 Accès aux informations du système
  • 7.1.1 Gestion des processus
  • 7.1.2 la fonction system
  • 7.1.3 les quotes inverses
  • 7.1.4 processus et descripteurs de fichiers
  • 7.1.5 mécanismes fork-exec
  • 7.2 Traitement des chaînes de caractères
  • 7.2.1 recherche et remplacement
  • 7.2.2 transformation de caractères individuels
  • 7.3 Tris personnalisés
  • 7.4 Structures de données élaborées via les références anonymes
  • 7.5 Scripts Perl dans un contexte web
  • 7.5.1 protocole HTTP
  • 7.5.2 schéma fonctionnel CGI
  • 7.5.3 module CGI
  • 7.5.4 méthodes GET et POST
  • 7.5.5 traitement de formulaires
  • 7.6 Accès aux bases de données
  • 7.6.1 Le Module DBI
  • 7.7 Quelques modules pour Windows
  • 7.7.1 Le module Win32
  • 7.7.2 Le module Win32API
  • 7.8 Gestion avancée des modules
  • 7.8.1 Créer un module non orienté objet
  • 7.8.2 Introduction à la programmation objet avec Perl
  • 7.8.3 Conception d'une classe
  • 7.8.4 Mise en oeuvre d'un module objet simple
  • 5 Les fonctions

    5.1 Présentation

    La création d'une fonction en Perl est on ne peut plus simple. elle se fait au moyen du mot-clé « sub » suivi d'un bloc.

    #!/usr/bin/perl -w
    sub simplesub {
      
    print "Bonjour\n";
      
    print "Une sub simple sans parametres\n";
    }
    simplesub();
    &simplesub;

    #Avec '&' , on est certain d'invoquer une sub et les parenthèses sont souvent facultatives , mais permettent de mieux délimiter les paramètres quand il y en a.
    &simplesub();

    5.2 Paramètres, visibilité et retour

    5.2.1 paramètres

    Les paramètres d'une fonction peuvent être illimités. La raison à cela est que la liste des paramètres est tout simplement une liste plate : le tableau @_. (cf. variables réservées)

    Chaque paramètre peut alors être extrait à l'intérieur de la sub comme on le fait pour toute liste:



    exemple avec shift:

    #!/usr/bin/perl -w
    sub dire {
      
    my $mot=shift;
      
    print "$mot\n";
    }
    dire(
    'bonjour');

    exercice: selon ce principe : faire une fonction à 5 paramètres.


    il arrive que l'on ne souhaite pas supprimer le paramètre du tableau @_ souvent parce qu'on souhaite y accéder ultérieurement par exemple. dans ce cas, il ne faut pas utiliser shift.

    Et l'extraction peut alors se faire ainsi.


    sub redire {
      
    my $mot = $_[0];
      
    print "$mot\n";
    }

    #ou encore directement sans recopie #dans une autre variable
    sub redire2 {
       
    print  "$_[0]\n";
    }
    redire(
    'bonjour');
    redire2(
    'ça va?');


    dans le cas de plusieurs paramètres on préférera l'affectation de plusieurs scalaires à partir de @_ sous forme de liste:

    #!/usr/bin/perl -w
    sub fenetre {
    my ($x,$y,$width,$hight,$color) = @_;
     foreach my $item qw(x y width hight color) {
      
    print "$item = " . eval('$' . $item) . "\n";
     }

    # ...;
    }
    fenetre(
    2,5,35,48,'rouge');


    Notez qu'il s'agit encore d'une copie de chaque argument dans des variables distinctes et que @_ n'est pas modifié.

    5.2.2 visibilité

    Toute sub perl est globale et sera donc visible de partout dans votre code.

    Cela signifie que vous pouvez placer son appel avant ou après la définition de la fonction.

    Cette règle se limite à votre programme. L' import de package ou l'utilisation des classes que nous allons voir par la suite obéit à d'autres règles.

    5.2.3 retour

    Une sub Perl peut renvoyer des données au moyen de l'instruction return;

    mais elle n'est pas obligatoire puisque la dernière expression valide de la sub est automatiquement renvoyée.

    Une sub Perl peut renvoyer toutes les structures Perl existantes c'est à dire des scalaires, des listes et des hashs, mais pour des objets complexes, il est nettement préférable d'utiliser les références.

    exemple open_read_close:

    #!/usr/bin/perl -w
    sub open_read_close {
    my $file = shift;
    unless (open (FILE,$file)){
      
    warn "Ne peut ouvrir $file : $!" ;
      
    return 0;
      }
     
    while (<FILE>)
     {
      
    print;
     }

    close(FILE);
    return 1;
    }
     if (open_read_close('/home/moi/txt/notes.txt')){
      
    print "OK : le fichier est lu!\n";
     }
     
    else {
      
    print "L'ouverture a échoué\n";
     }

    return n'est pas obligatoire comme dernière instruction, exemples :

    #!/usr/bin/perl -w
    sub  testnum {
     
    return 1 if  $_[0] =~ /^[0-9]+$/;
    #En dernière instruction return n'est pas obligatoire.
     
    0;
    }

    sub anti 'anticonstitutionnellement';}
    sub douze 12; }
    ##############ROUTINES##############
    print testnum('toto') . "\n";
    print testnum(32) . "\n";
    print douze() . "\n";
    print &anti  . "\n";


    5.3 Notion de variables semis-privées


    5.4 Retour scalaire ou liste selon contexte

    Perl peut créer des fonctions qui s'adaptent aux contexte.

    Autrement dit si l'appelant veut une liste : je lui renvoie une liste s'il veut un scalaire : je lui retourne un scalaire. C'est déjà le cas de nombreuses fonction natives de Perl comme grep:

    my @newliste=grep(/motif/,@liste);

    Dans ce contexte on demande à grep de renvoyer une liste et @newliste contiendra tous les éléments de @liste qui contiennent /motif/.

    Mais que se passe t-il si j'écris:

    my $chose = grep(/motif/,@liste);

    A ce moment grep sait qu'il ne peut ni ne doit renvoyer une liste mais son prototype (sa définition interne) lui dit qu'il doit renvoyer le nombre d'éléments qui contiennent le motif.

    $chose contiendra alors un nombre qui peut être contenu par un scalaire.

    La fonction wantarray appliquée juste avant la sortie d'une fonction permet de créer une fonction locale ayant le même comportement et s'adapter au contexte; ainsi la fonction grep pourrait s'écrire ainsi:


    #!/usr/bin/perl -w
    use strict;
    sub mongrep {
     
    my $motif=shift;
     
    my @out;
     
    foreach (@_) {
      
    push(@out,$_if /$motif/;
     }
     
    return  (wantarray() ? (@out) : scalar(@out) );
    }

    my @set =   mongrep(qr/^[EAZ]TERE_CODE/,
    qw(ATERE_CODE ZTERE_CODE UTERE_CODE));
    foreach my $one (@set){
     
    print "$one\n";
    }

    my $nb_set = mongrep(qr/^[EAZ]TERE_CODE/,
    qw(ATERE_CODE ZTERE_CODE UTERE_CODE));
    print "$nb_set\n";


    Autre exemple : passer une liste en majuscules

    #!/usr/bin/perl -w
    my $v1 = 'tutoriel';
    my $v2 = 'animal';
    my ($v3$v4) = upcase($v1$v2);  # cela ne change pas $v1 et $v2
    print "$v3\n";
    print "$v4\n";
     sub upcase {
             
    return  unless defined wantarray;  # contexte vide, ne fait rien
             
    my @parms = @_;
             
    foreach (@parms) { tr/a-z/A-Z/ }
             
    return wantarray ? @parms : $parms[0];
     }

    5.5 Utilisation de références dans les arguments

    Il est possible de référencer les arguments. Cela permet de les manipuler à distance.

    Il n'y a d'ailleurs pas vraiment d'autres solutions pour les objets structurés avec des références imbriquées.

    Tout d'abord, sachez que la modification de @_ agira directement sur les éléments transmis, à condition bien sur qu'il ne s'agit pas de constantes littérales:


    my $n=10;
    ajouter($n,3);
    print "$n\n";
    #affiche 10;
    ajouter(5,2); #erreur car 5 est une constante littérale qui ne peut être modifiée.
    #####################
    sub ajouter {
    $_[0] += $_[1];
    }


    cette propriété est pratique si l'on souhaite, par exemple modifier une liste complète:

    #!/usr/bin/perl -w
    use strict
    ;
    my @liste_a_nettoyer;
    @liste_a_nettoyer=remplir('ls -1tr'); #rempli la liste
    #nettoie la liste

    nettoyer_liste(
    @liste_a_nettoyer);
    #et la liste est propre!
    print_liste(@liste_a_nettoyer);
    sub nettoyer_liste {
     
    foreach (@_){
        s,^\s*,,;
        s,\s*
    $,,;
        s,PUB,,;
    #enlève PUB
     }

    #supprime les répertoires courants '.' et précédents '..'
     @_ = 
    grep(!/^\./,@_);
    }

    sub remplir {
    my $cmd=shift;
    @_=
    `$cmd`;
    }

    sub print_liste {
     
    foreach (@_){
      
    print "$_\n";
     }
    }

    En effet toute action sur la ligne courante $_ va modifier l'élément du tableau courant,en occurrence @_ et puisque celui-ci est directement lié à @liste_a_nettoyer, @liste_a_nettoyer sera modifié aussi.


    Si l'on souhaite pouvoir modifier des valeurs issues de constantes littérales, il suffit de copier les arguments de @_ dans de nouvelles variables, et l'on devra dans ce cas retourner un résultat puisque les constantes ne sont pas modifiables.


    sub ajouter {
    my ($a,$b) =@_;
    $a += $b;
    return $a;
    }

    Ceci est pratique pour les listes plates et les scalaires, mais à très vite ses limites lorsqu'il s'agit de hashs ou d'objets complexes référencés. De plus si vous avez plusieurs objets, (liste ou hash) rien ne les différenciera puisque la liste plate des arguments @_, ne peut qu'être unique.

    Dans ce cas la seule solution est de passer des référencer les objets, vous ne transmettez plus une liste, mais un seul scalaire : une référence.

    Voici une façon de le faire:

    exemple avec 2 listes

    #!/usr/bin/perl -w
    use strict
    ;
    my (@lst,@autre_liste);
    traitement(
    \@lst,\@autre_liste);
    print_liste(\@lst);
    print_liste(\@autre_liste);

    ################# ROUTINES ####################
    sub traitement {
    #on récupère les 2 références
    #notez que ce n'est pas obligatoire : on peut agir directement 
    #sur $_[0] ou $_[1], cela rend toutefois l'écriture beaucoup plus simple

    my ($a,$b)=@_;
     
    #insère 10 items dans chaque liste
     
    for my $i (0 .. 10){
                 
    push(@{$a},'item (lst) ' . $i);
                 
    #notez qu'il faut dé-référencer
                 
    push(@{$b},'item (autre liste) ' . $i)
                }
    }

    sub print_liste {
       
    foreach (@{$_[0]}){
          
    print "$_\n";
       }
    }


    exemple avec une liste et un hash

    #!/usr/bin/perl -w
    use strict
    ;
    my (@lst,%mon_hash);
    traitement(
    \@lst,\%mon_hash);
    print_liste(\@lst);
    print "--------\n";
    print_hash(\%mon_hash);
    ################## ROUTINES ###################
    sub traitement {
    #on récupère les 2 références
    #notez que ce n'est pas obligatoire : on peut agir directement 
    #sur $_[0] ou $_[1], cela rend toutefois l'écriture beaucoup plus simple

    my ($a,$b)=@_;
     
    #insère 10 items dans chaque liste
     
    for my $i (0 .. 10){
                 
    #notez qu'il faut dé-référencer
                 
    push(@{$a},'item (lst) ' . $i);
                }
       
    %$b = (
                
    Nom => 'DUPONT',
                
    Prenom => 'Julien',
                
    Age    => 27,
                
    Sexe   => 'Homme'
              );
    }

    sub print_liste {
       
    foreach (@{$_[0]}){
          
    print "$_\n";
       }
    }

    sub print_hash {
       
    foreach my $k (keys %{$_[0]}){
        
    print "$k => $_[0]->{$k}\n";
       }
    }


    5.6 Les références sur fonctions

    Il peut être pratique de référencer les fonctions. Ceci permet des les lier à des scalaires, voir à d'autres objets complexes. On référence les fonctions afin de pouvoir différer facilement des actions, et les insérer, dans des objets plus ou moins complexes, voyons ceci en pratique.


    5.6.1 références sur une sub nommée

    Cet exemple démontre et explique comment créer une référence sur fonction et comment la lancer.

    #!/usr/bin/perl -w
    use strict
    ;
    sub masub {
     
    my $param = shift;
     
    print "sub : masub ";
     
    print "param : $param\n";
    }

    ##################################################
    #déclare la référence

    my $s=\&{'masub'};
    #méthodiquement :
    #1 : Ecrire le nom de la sub sous forme de chaîne 'masub'
    #2 : la placer entre accolades {'masub'} 
    #3 : placer & devant pour indiquer qu'il s'agit d'une sub perl : &{'masub'};
    #4 : référencer le tout avec l'antislash : \&{'masub'} : vous y êtes.
    #5 : affecter le tout à une variable
    #APPELS : plusieurs formes possibles
    #premier type d'appel  : on spécifie qu'un s'agit d'une sub au moyen de '&';

    &{$s}('un');
    #puisque $s est une expression simple : peut se simplifier ainsi, :
    &$s('un');
    #deuxième type d'appel : on utilise '->' pour dé-référencer, (idem en C et C++);
    $s->('un');
    #Notez que à bien y regarder, le mécanisme de référencement/dé-référencement des subs,
    #est le même que pour les listes et les hashs

    5.6.2 références sur sub anonyme

    cela peut se faire ainsi :

    my $masub = sub {
    ...
    ...
    }

    pour l'appel, il y a deux solutions : il faut un moyen de préciser que la référence est une sub.

    &$masub;

    ici on peut ajouter les parenthèses, si l'on a des paramètres.

    $masub->();

    et on peut si besoin, passer des paramètres dans les parenthèses. On les récupère exactement de la même façon avec shift ou @_, dans la sub anonyme.

    Puisqu'une référence de sub peut être contenue par n'importe quel scalaire, elle peut au même titre être l'élément d'une liste ou d'un hash.


    Alors ce type de construction par exemple, est tout a fait possible :

    #!/usr/bin/perl -w
    my %calcul;
    %calcul= (
     
    'sum' => sub {($_[0] + $_[1])},
     
    'mult'  => sub {($_[0] * $_[1])},
     
    'soust' => sub { ($_[0] - $_[1])}
    );

    my $file='actions.txt';
    open(FILE,$fileor die "Ne peut ouvrir $file : $!";
    while (<FILE>){
      
    chomp;
      
    my ($action,@values) = split(/\s+/);
       
    print "l'action est $action, ";
       
    print 'valeurs : ' . join(' et ' ,@values) ;
       
    my $result = $calcul{$action}->(@values);
       
    print ', le résultat est : ' . "$result\n";
     }

    exercice:

    Pour l'addition et la multiplication : faire la même chose avec un nombre de valeurs illimitées.

    6 Les modules

    6.1 Les fonctions intégrées et modules

    6.1.1 Simple collection de routines

    A l'origine perl utilise l'instruction require pour importer un autre fichier. Alors, toute variable globale et sub du fichier importée est accessible au fichier principal.

    Exemple de fichier importé :

    #fichier contenant des routines : Outils.pm
    our $ma_var='Une variable';
    sub monter {
     println(
    "Je monte.");
    }

    sub demonter {
     println( 
    "Je démonte.");
    }

    sub faire {
     println( 
    "Je fait.");
     }

    sub println {
     
    print $_[0] . "\n";
    }

    Programme qui importe et utilise ce fichier:

    #!/usr/bin/perl -w
    #fichier programme principal : main.pl
    use strict;
    require 'Outils.pm';
    monter();
    demonter();
    faire();

    #désactive le use strict pour les variables
    no strict 'vars';
    print "$ma_var\n";


    6.2 Utilisation d'un module non orienté objet

    6.2.1 notion de package

    Il arrive cependant que l'on souhaite isoler les objets et subs de notre fichier afin d'y accéder de manière groupée. Dans ce cas, il est préférable de créer un package au moyen de l'instruction du même nom, en première ligne du fichier importé. Ceci se fait ainsi:

    package Poutil;

    Ainsi puisque tous les symboles seront déclarés dans un package, ils ne feront plus partie du package courant: sachez que toute variable appartient à un package et que les variables de votre script sont dans le package main et accessibles aussi de la sorte :

    print main::$var . "\n"; => print $var . "\n";

    &main::masub(); => masub();

    Voici donc l'utilisation d'un package non orienté objet:

    package Poutils;
    our $ma_var='Une variable';
    sub monter {
     println(
    "Je monte.");
    }

    sub demonter {
     println( 
    "Je démonte.");
    }

    sub faire {
     println( 
    "Je fait.");
     }

    sub println {
     
    print $_[0] . "\n";
    }

    1;

    Note : En principe tout package doit retourner 1 , il faut pour cela écrire 1; en fin du package.


    Et voici ce que devient le script principal:

    #!/usr/bin/perl -w
    #fichier programme principal : main_poutils.pl
    use strict;
    require 'Poutils.pm';
    Poutils::monter();
    Poutils::demonter();
    Poutils::faire();

    my $nouvelle = "test";
    print "$Poutils::ma_var\n";
    #les variables du programme principal sont dans le package main
    print "$main::nouvelle\n";

    Ainsi les subs , les variables, les hashs, et listes du package Poutils.pm ne sont plus accessibles directement, puisqu'elles se trouvent être dans le package Poutils. Il existe un moyen de les rendre accessible dans le package courant au moyen des typeglobs.

    En effet si je veux que la sub monter soit accessible dans main il me suffit d'écrire ceci:

    *main::monter = *Poutils::monter;

    Ainsi monter pourra être appelé directement:

    &monter();

    puisqu'il sera dans le package main.

    C'est ce que l'on appelle l'import (de symboles) mais vu coté package on l'appelle export et ceci permet de mieux contrôler ce que l'on souhaite rendre accessible directement ou pas en effet, on ne souhaite pas forcément rendre tous les objets du package accessibles, par exemple, la sub println n'est pas forcément nécessaire à l'extérieur du package puisqu'elle sert au subs internes, pour afficher.

    6.2.2 L'instruction use

    Avec l'évolution de Perl, est venue l'instruction use qui permet de mieux gérer l'import/export de symboles.

    En réalité l'instruction

    use Pkg;

    fait tout ceci de manière plus compacte :

    BEGIN{
    require 'Pkg.pm';
    Pkg->import() if Pkg->can('import');
    }

    BEGIN est un bloc qui s'exécutera en tout premier dans votre code (ou qu'il soit placé).

    Avec use, import importera les symboles qui seront exportés coté package. Coté package pour exporter des symboles , il faut faire 2 choses :


    Voiçi la façon de le faire:

    package Pkg;
    use Exporter; #importe la package Exporter
    @ISA = qw(Exporter); #fait hériter le package Pkg de Exporter : lui permet d'exporter
    @EXPORT = qw(&sub1 &sub2 &sub3 $mavar); #exporte les symboles

    6.2.2.1 Localisation des modules

    Perl recherchera par défaut votre package dans le répertoire courant et dans les répertoires contenus dans @INC (cf variables réservées de Perl).

    Vous pouvez décider de mettre tous vos paquets personnels dans un chemin dédié, et dans ce cas vous devez modifier cet environnement afin qu'il sage ou les trouver.

    Ceci peut être fait de différentes 4 manières :

    Dans votre environnement extérieur:


    1. export PERL5LIB=''$PERL5LIB:/home/user/perl/malib'';

    2. sous Windows : utiliser set PERL5LIB=%PER5LIB%;c:\home\moi\perl\malib

    3. dans votre script écrire au début use lib '/home/moi/perl/malib';

    4. dans le script écrire push(@INC,'/home/moi/perl/malib');




    La première méthode est de loin la meilleure car les 2 autres vous obligerons à réécrire cette instruction à chaque fois dans votre script.

    6.2.2.1.1 package dans un sous-répertoire

    En supposant que vous ayez un package dont le chemin est celui-ci.

    /home/moi/perl/malib/PerlIO/Via/Vcsa.pm

    et si vous avez modifié @INC comme précisé au point précédent, alors vous devrez importer votre paquet comme suit:

    use PerlIO::Via::Vcsa;

    Cette notation n'a aucun effet sur l'objet , il faut juste la considérer comme le remplacement du séparateur de répertoire pour localiser votre module à partir d'un des chemins de base de @INC.

    Un module non orienté objet qui exporte des symboles peut donc se faire ainsi :

    package Uoutils;
    use Exporter; #Importe l'Exporter
    @ISA = qw(Exporter);
    @EXPORT=qw(&monter &demonter &faire $ma_var);
    our $ma_var='Une variable';
    sub monter {
     println(
    "Je monte.");
    }

    sub demonter {
     println( 
    "Je démonte.");
    }

    sub faire {
     println( 
    "Je fait.");
     }

    sub println {
     
    print $_[0] . "\n";
    }

    1;

    Et voici la façon d'utiliser ce package:

    #!/usr/bin/perl -w
    #fichier programme principal : main_uoutils.pl
    use Uoutils;
    use strict;
    monter();
    demonter();
    faire();

    print "$ma_var\n";

    Notez que Exporter permet aussi d'utiliser le tableau @EXPORT_OK, celui-ci fonctionne comme @EXPORT, mais il oblige coté du coté de l'import, à mentionner tout symbole après le use comme suit:

     use Uoutils qw(monter demonter);

    Ne pensez pas que @EXPORT_OK est moins utilisé que @EXPORT, cela devrait même être l'inverse car @EXPORT_OK oblige à mentionner l'import des symboles coté appelant avec use. C'est une sécurité supplémentaire et cela nous laisser la possibilité d'importer seulement ce dont nous avons besoin dans le package.

    Il est aussi possible d'exporter des tags. Les tags sont des groupes de symboles contenus dans un hash et exportable par le hash %EXPORT_TAG.

    Nous sommes partis de l'instruction require qui permet d'importer un simple fichier, pour arriver à l'instruction use qui permet d'utiliser les symboles d'un package.

    Il convient alors autant que possible d'utiliser use pour l'utilisation des packages.

    Vous savez à présent ce qu'est un package, comment fonctionne le mécanisme d'import et comment utiliser un package non orienté objet.

    Nous allons voir à présent comment créer et utiliser un module simple Orienté Objet.

    6.2.2.1.2 Utilisation de %EXPORT_TAGS

    Il est possible au moyen du hash %EXPORT_TAGS, d'exporter un groupe de symboles.

    Ceci peut se faire ainsi à l'intérieur du package :



    our %EXPORT_TAGS = ( 'all' => [ qw(
            JS_PROP_PRIVATE 
            JS_PROP_READONLY        
            JS_CLASS_NO_INSTANCE
    )
     ] );
    #Puis invoquer la méthode export_ok_tags
    # ou export_tags du module Exporter pour la clé du tag :

    Exporter::export_ok_tags(
    'all');

    L'appel se fait ainsi:


    use Monpkg qw(all);
    if ($JS_PROP_PRIVATE eq 'normal') {
    }


    6.3 Utilisation d'un module orienté objet

    6.3.1 Notion d'objet

    La programmation Orientée Objet (POO) est apparue au milieux des années 70 et s'est étendue au début des années 80.

    Avant cela il était possible de faire de l'objet et de produire une programmation structurée de la même manière, comme on le fait toujours en langage C. Malheureusement les langages non objets ont deux inconvénients pour cela:

    Hors en programmation et d'autant plus que le projet est important et est produit en équipe, l'aspect présentation et communication est d'une importance capitale.

    Ainsi les langages POO s'adaptent mieux à la modèlisation UML par exemple.

    Il est possible de présenter des interfaces (des fonctionnalités) sans entrer dans le détail du code.

    6.3.1.1 Instance

    La différence entre la collection de routines ou langage orienté fonctions (non objet) et l'objet est la notion d'instance.

    Autrement dit tout langage Orientée Objet crée des instances d'objets.

    On parle alors de durée de vie et d'état transitoire d'un objet.

    Dans la plupart des langages Orientés Objet, l'instance est une référence ou un pointeur statique, c'est à dire qu'il reste en mémoire et garde la même adresse pendant toute la durée de vie de l'objet jusqu'à sa destruction.

    Toutes les fonctions sont alors greffées sur cette instance et on ne parle plus de fonctions mais on les nommes des méthodes, (simple question de langage pour ne pas dire des fonctions ).

    Plus concrètement voici comment cela se présente en Perl.

    #Importe le package Window, qui est développé sous forme de classe,
    #nous allons voir comment par la suite.

    use Window;
    #pour créer une nouvelle instance, on fait souvent appel à la méthode new.
    my $w1 new Window(1,1,50,100,'blue');
    #$w est à présent une instance de l'objet Window;
    #Une autre forme d'appel à new.

    my $w2 = Window->new(3,6,20,20,'red');
    A présent : appel des méthodes

    $w1->draw(); #dessine la fenêtre
    $w2->move_right(10);#déplace la fenêtre $w2 de 10 unités vers la droite.
    $w2->destroy();#détruit l'instance
    $w1->destroy();#idem
    #A présent, il n'est plus possible d'appeler des méthodes sur w1 ou w2.


    6.3.2 Mise en oeuvre d'un module objet simple

    6.3.2.1 notion de constructeur

    En perl, une classe est un package avec un mécanisme, le plus souvent une méthode spéciale, le constructeur, qui permet de créer une instance. Pour des raisons de bon sens on nomme cette sub new ou create, par exemple, mais en Perl il n'y a aucune restriction.

    En interne de la classe, l'instance n'est jamais qu'une référence anonyme, le plus souvent un hash, mais cela ne suffit pas : il faut que cette référence soit bénie au moyen de la fonction bless.

    Voyons cela en pratique avec la classe Fenetre:

    package Fenetre;
    #Le constructeur new
    sub new {
    my $name = shift#Le premier paramètre donne le nom du package
    my $self = {}; #Référence sur un hash anonyme
    #la fonction bless étant la dernière instruction de la sub new
    #elle renvoie le premier paramètre

    #
    $self bénie qui va constituer l'instance en externe.
    bless($self$name);
    }

    #Méthode init
    sub init {
     
    my $self = shift;
     
    print "initialisation\n";
    }

    #Méthode draw
    sub draw {
     
    my $self = shift#récupère l'instance en interne
     
    $self->init(); #appel la sub init interne
     
    print "Je dessine\n";
    }

    #Méthode set_color
    sub set_color #Un setteur
     
    my ($self$color)=@_;
     
    $self->{color}=$color;
    }

    # ...
    # Autres méthodes éventuelles
    # ...

    1;


    Exercices:

    1. Copier cette classe et l'utiliser : créer une instance et lancer toutes les méthodes sauf la méthode init.

    2. Modifier la classe : Ajouter une méthode get_color qui renvoie le paramètre color. Tester cette méthode.

    3. Ajouter une méthode affiche_params qui affiche tous les paramètres de la classe. Tester cette méthode.

    4. Après avoir instancié la classe, Utiliser le module Data::Dumper et analyser ce que vous voyez.


    6.3.2.2 un constructeur plus sophistiqué

    Le constructeur doit parfois définir des valeurs par défaut, pour cela il faut quelque-peu modifier la définition du hash anonyme.

    package Window;
    sub new {
        
    my $this   = shift;
        
    my $class = ref($this) || $this;
        
    die "odd number of elements to new sub." if ( (scalar(@_) % 2 ) != 0);
        
    my $self  = {
        
    color => 'white' , # Couleur par défaut
        
    fill => 0 , # Si on doit remplir l'intérieur
        
    char => ' ',    # avec quel caractère
        
    'hidden' => 1,  # fenêtre cachée par défaut
        @_

    # Paramètres additionnels : ils peuvent écraser les
    #
     valeurs par défaut initiales;
        };
         
    bless $self$class;
        
    return $self;
    }

    #Utilisation d'un setter
    sub set_color {
     
    my ($self,$color)=@_;
     
    $self->{color}=$color;
     }

    #....
    1;


    L'appel au constructeur de notre classe pourra donc se faire ainsi:

    use strict;
    use Window;
    my $w new Window(color => 'blue' offset => 18);

    Dans ce cas, l'attribut color de la classe sera écrasé par 'blue' au lieu de sa valeur par défaut qui est

    'white'.

    Exercices:

    1. Refaire les mêmes exercices que précédents pour cette classe.

    6.3.2.2.1 Création et accès aux attributs

    Dites-vous qu'une fois votre référence de hash créée, TOUT ce que vous ajoutez doit se greffer dessus. Ainsi les attributs sont une simple clé supplémentaire de votre hash anonyme qui peut se faire ainsi;

    use MaClass;
    my $machin new MaClass(flag => 'z' offsets => [25]);
    #Ajout d'un nouvel attribut
    $machin->{'color'} = 'red';

    Il n'y a pas de limitte du nombre d'attributs que vous pouvez déclarer de la sorte, sauf ... la mémoire.

    Mais il est nettement préférable d'utiliser des getters et setters comme dans l'exemple précédent. Notez quie si vous avez programmé en C++, Python, ou Java, vous serez tentés d'ajouter des variables à l'extérieur dans le module. Cela est une grosse erreur car dans tous les cas elles seront globales au niveau module, c'est à dire que toutes vos instances agirons sur la même variable, une fois l'import du module fait par use. Ce n'est probablement pas ce que vous voulez puisqu'un attribut comme tous les membres d'une classe ont une vie propre lié à chaque instance. En C++ ou Java cela reviendrai à faire une déclaration statique dans un constructeur par exemple:

    static  int i;

    6.3.2.3 méthodes orientées objet ET orientées fonctions

    Certains packages comme le module CGI, permetent une double programmation à la fois orientée objet et orientée fonctions.l'utilisation se fait ainsi, orientée objet:

    #!/usr/local/bin/perl -w
       
    use CGI;
                                             
    # chargement du module CGI
       
    $q new CGI;
                                             
    # creation d'un nouvel objet CGI
       
    print $q->header,
                                             
    # creation de l'en-tete HTTP
              
    $q->start_html('hello world'), # debut du HTML
              
    $q->h1('hello world'),
                                             
    # titre de niveau 1
              
    $q->end_html;
                                             
    # fin du HTML

    et ainsi Orientée fonctions:

    #!/usr/local/bin/perl
       
    use CGI qw/:standard/;
                                         
    # chargement des fonctions standard de CGI
       
    print header,
                                         
    # creation de l'en-tete HTTP
              start_html(
    'hello world'), # debut du HTML
              h1(
    'hello world'),
                                         
    # titre de niveau 1
              end_html;
                                         
    # fin du HTML



    Pour créer de telles méthodes, il faut vérifier si le premier paramètre de la méthode est une référence de classe et si cette référence donne le nom du package ou pas.Il suffit ensuite d'extraire ou pas cette référence. La fonction Perl ref permet de déréférencer directement un scalaire et de vérifier en même temps si ce scalaire est bien une référence.

    Voiçi comment ceci peut être réalisé en ajoutant une méthode printmsg à un parametre à notre classe, qui pourra être appelée à la fois sous forme de méthode ou de fonction non objet.

    package Fenetre;
    use Exporter;
    @ISA=qw(Exporter);
    @EXPORT_OK = qw(&printmsg);
    #Constructeur de fenêtre
    sub new {
    my $name = shift;
    my $self = {};
    #bless étant la dernière instruction de la sub new
    #il renvoie le premier paramètre $self bénie qui constitue l'instance en externe.

    bless($self$name);
    }

    sub init {
     
    my $self = shift;
     
    print "initialisation\n";
    }

    sub draw {
     
    my $self = shift#récupère l'instance en interne
     $self->init(); #appel la sub init interne
     
    print "Je dessine\n";
    }

    sub set_color {
     
    my ($self$color)=@_;
     
    $self->{color}=$color;
    }

    # sub printmsg orientée objet ET fonctions.
    sub printmsg {
    my ($name,$self);
    # vérifie si le premier parametre est
    # une référence du nom de la classe

     
    if (($name=ref($_[0])) eq 'Fenetre'){
      
    $self = shift;
     }
     
    my $msg = shift;
     
    print "[$msg]\n";
    }

    # ...
    # Autres méthodes éventuelles
    # ...

    1;


    Exercice:

    Localisez le module CGI.pm dans votre système et regardez comment ceci est réalisé.

    6.3.2.4 La méthode AUTOLOAD

    Cette méthode entièrement en majuscules est une méthode magique qui se comporte comme si elle avait le nom de toutes les méthode non existantes du module . En effet si vous appelez la méthode ou la fonction chmol de votre module et que celle-ci n'existe pas, mais que votre module a une sub AUTOLOAD , la méthode AUTOLOAD sera appelée.

    Il est possible de connaître le nom de la fausse méthode appelée au moyen de la variable scalaire du même nom : $AUTOLOAD.

    Cette technique permet de faire des appels virtuels et calculés en fonction du contexte, très puissants vers de vraies fonctions ou méthodes en fonction du certaines conditions. On peut s'en servir par exemple pour intercepter l'appel d'une fonction afin d'aiguiller la la méthode d'un package A dans un cas et d'un package B dans l'autre.

    L'inconvénient est que cela demande une relecture du code de la méthode AUTOLOAD assez poussée parfois.

    Exemple:


    6.3.3 Conclusion

    Nous avons vu l'essentiel pour créer une classe Perl orientée objet et l'utiliser. Il serait inutile d'en dire plus pour l'instant. Si vous n'avez pas tout saisi, contentez-vous de créer des classes en appliquant cette méthode et dites-vous qu'une meilleure compréhension viendra avec le temps et la pratique.

    Si certaines parties de la documentation Perl vous dépassent, passez les pour l'instant et attendez d'avoir un peu plus de recul pour y revenir.

    Pour terminer, nous constatons que Perl est un langage très souple pour la programmation Orientée Objet et qu'il a l'avantage de ne pas s'imposer comme un langage tout objet : par exemple comme le langage Java. Il laisse au programmeur une liberté de conception et d'utilisation.

    La documentation Perl décrit aussi l'Objet à sa manière dans ces fichiers.

    6.3.3.1 Documentation officielle Perl Objet à consulter

    Ces documents vous aiderons à comprendre l'Objet en Perl. Voyez les premiers et essayez les suivants, s'ils ne vous conviennent pas.
    perlboot - Tutoriel pour l'orienté objet à destination des débutants

    perltoot - Tutoriel orienté objet de Tom.

    perltooc - Le tutoriel de Tom pour les données de classe OO en Perl

    perlbot - Collection de trucs et astuces pour Objets (the BOT)

    perlobj - Objets en Perl