IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

Fonctions imbriquées - références


Sujet :

Langage Perl

  1. #1
    Yux
    Yux est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 105
    Points : 74
    Points
    74
    Par défaut Fonctions imbriquées - références
    Salut,

    Je crois avoir saisi l'essentiel en ce qui concerne la confidentialité des variables dans les programmes perl, mais je me pose quelques questions au sujet des appels de fonctions à partir d'autres fonctions, et en particulier à propos de l'usage des références dans ce cas de figure précis. Prenons le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/usr/bin/perl -w
     
    use strict;
     
    my ($a,$b) = (0,1);
     
    &function1($a);
    &function2($b);
     
    sub function1 {
            my $arg1 = shift;
            print "$arg1\n";
    }
     
    sub function2 {
            my $arg2 = shift;
            print "$arg2\n";
            &function1($a);
    }
    La sortie est :
    0
    1
    0
    La variable $a est donc bien "vue" dans le corps d'une fonction elle-même imbriquée dans une autre fonction (ce qui paraît normal, pas de surcharge locale, tout ça...)

    Le problème est que je n'arrive pas à obtenir le même comportement avec l'usage de références. J'écris un démon perl et je souhaite qu'il relise sa conf en recevant un signal SIGHUP. D'une façon générale, le démon lit sa conf à partir d'un fichier par le biais de la procédure get_conf :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    # Mailer
    my $mailer = {};
     
    # Logger
    my $logger = {};
     
    # Cibles
    my $http_hosts = [];
    my $smtp_hosts = [];
    my $imap_hosts = [];
     
    &get_conf ($mailer,$logger,$http_hosts,$smtp_hosts,$imap_hosts);
     
    sub get_conf {
            my $mailer     = shift;
            my $logger     = shift;
            my $http_hosts = shift;
            my $smtp_hosts = shift;
            my $imap_hosts = shift;
     
            my $conf = AppConfig -> new (
                    'mailer_smtp'      => {ARGCOUNT => 1},
                    'mailer_sender'    => {ARGCOUNT => 1},
                    'mailer_recipient' => {ARGCOUNT => 1},
                    'logger_ident'     => {ARGCOUNT => 1},
                    'logger_logopt'    => {ARGCOUNT => 1},
                    'logger_facility'  => {ARGCOUNT => 1},
                    'http_host'        => {ARGCOUNT => ARGCOUNT_LIST},
                    'smtp_host'        => {ARGCOUNT => ARGCOUNT_LIST},
                    'imap_host'        => {ARGCOUNT => ARGCOUNT_LIST}
            );
     
            $conf -> file ('/etc/monitor/monitor.conf');
     
            # Mailer
            $mailer->{SMTP} = Net::SMTP -> new ($conf -> mailer_smtp ());
            $mailer->{SMTP} -> mail ($conf -> mailer_sender ());
            $mailer->{SMTP} -> to ($conf -> mailer_recipient ());
            $mailer->{SENDER} = $conf -> mailer_sender ();
            $mailer->{RECIPIENT} = $conf -> mailer_recipient ();
     
            # Logger
            $logger->{IDENT} = $conf -> logger_ident ();
            $logger->{LOGOPT} = '';
            $logger->{FACILITY} = $conf -> logger_facility ();
     
            # Cibles
            @$http_hosts = @{$conf -> http_host ()};
            @$smtp_hosts = @{$conf -> smtp_host ()};
            @$imap_hosts = @{$conf -> imap_host ()};
    }
    J'ai donc écrit le handler suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    sub sig_hup {
            &get_conf ($mailer,$logger,$http_hosts,$smtp_hosts,$imap_hosts);
    }
     
    $SIG{HUP} = \&sig_hup;
    Cela ne fonctionne pas, j'obtiens les erreurs suivantes :

    Global symbol "$mailer" requires explicit package name at ./monitor_test.pl line 62.
    Global symbol "$logger" requires explicit package name at ./monitor_test.pl line 62.
    Global symbol "$http_hosts" requires explicit package name at ./monitor_test.pl line 62.
    Global symbol "$smtp_hosts" requires explicit package name at ./monitor_test.pl line 62.
    Global symbol "$imap_hosts" requires explicit package name at ./monitor_test.pl line 62.
    Execution of ./monitor_test.pl aborted due to compilation errors.

    Quelqu'un pourrait-il m'en dire plus, je ne comprends pas trop cette différence de comportement entre variables et références.

    Merci pour vos réponses !

  2. #2
    Membre chevronné
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2003
    Messages
    1 572
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 572
    Points : 2 014
    Points
    2 014
    Par défaut
    Je crois que pour le début de ta fonction, tu devrais faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    sub get_conf {
            my ($mailer,$logger,$http_hosts,$smtp_hosts,$imap_hosts) = @_;
    A essayer.

  3. #3
    Membre actif
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    546
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 546
    Points : 219
    Points
    219
    Par défaut
    Je trouve ton code pas très clair....
    Je comprends bien ton pb, mais essaies plutôt de changer le nom des variables
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
            my $mailer     = shift;
            my $logger     = shift;
            my $http_hosts = shift;
            my $smtp_hosts = shift;
            my $imap_hosts = shift;
    dans ta fonction... Par ce que là, à la lecture, on s'y perd...

    Jérôme
    Jérôme

  4. #4
    Yux
    Yux est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 105
    Points : 74
    Points
    74
    Par défaut
    Salut,

    Merci pour vos réponses... Je me suis peut-être mal exprimé mais la fonction get_conf() fonctionne parfaitement. Je pourrais effectivement utiliser l'écriture proposée par Arioch plutôt que de "shifter" les arguments un à un mais le résultat serait le même. Elle ne fonctionne pas dans le cas précis ou je l'invoque à partir du handler (c'est-à-dire dans le cas ou elle est imbriquée dans la fonction sig_hup). A ce moment là, les différentes références que je tente d'utiliser ne sont plus vues par la fonction.

    Sinon pour info, il s'agit d'un démon pour monitorer les services http, smtp et imap sur différentes machines.

    Quand un service tombe, l'info est loguée et un mail est envoyé via Net::SMTP.

    Donc :

    my $mailer --> référence anonyme vers hachage, contient toute les informations relatives au "mta" créé à l'aide de Net::SMTP
    my $logger --> contient les informations relatives à l'objet destiné à créer les logs (module Sys::Syslog)
    Les variables du type $https_hosts sont des références vers des listes d'hôtes (machines sur lesquelles il faut monitorer le service concerné).

    Pour en revenir à mon problème, je crois qu'on peut créer des références sur fonction, je vais essayer ça.

  5. #5
    Membre du Club
    Inscrit en
    Octobre 2005
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 47
    Points : 56
    Points
    56
    Par défaut Reférences
    A priori, le problème n'a rien à voir avec le fait que la sub soit appellée par une référence. Vu les erreurs, il faudrait savoir si la fonction est appellée dans le même package que là où elle a été définie.

  6. #6
    Yux
    Yux est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 105
    Points : 74
    Points
    74
    Par défaut
    Salut chostrama,

    L'ensemble du programme est contenu dans un unique fichier ; il ne devrait donc pas y avoir de problème à ce niveau là...

  7. #7
    Membre du Club
    Inscrit en
    Octobre 2005
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 47
    Points : 56
    Points
    56
    Par défaut
    On dirait quand même que les variables qui sont les arguments de get_conf() ne sont pas visibles quand sig_hup() est appelé.

    Es-tu sûr qu'ils ne sont pas définis à l'intérieur d'un autre bloc de code qq part?

  8. #8
    Yux
    Yux est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 105
    Points : 74
    Points
    74
    Par défaut
    Non, non, les différentes variables passées en arguments sont définies dans le corps du programme. En gros, ça donne ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    # Mailer
    my $mailer = {};
     
    # Logger
    my $logger = {};
     
    # Cibles
    my $http_hosts = [];
    my $smtp_hosts = [];
    my $imap_hosts = [];
     
    &get_conf ($mailer,$logger,$http_hosts,$smtp_hosts,$imap_hosts);
     
    sub sig_hup
    {
            &get_conf ($mailer,$logger,$http_hosts,$smtp_hosts,$imap_hosts);
    }
     
    $SIG{HUP} = \&sig_hup; 
     
    sub get_conf
    {
            my $mailer = shift;
            my $logger = shift;
            my $http_hosts = shift;
            my $smtp_hosts = shift;
            my $imap_hosts = shift;
     
            my $conf = AppConfig -> new (
                    'mailer_smtp'      => {ARGCOUNT => 1},
                    'mailer_sender'    => {ARGCOUNT => 1},
                    'mailer_recipient' => {ARGCOUNT => 1},
                    'logger_ident'     => {ARGCOUNT => 1},
                    'logger_logopt'    => {ARGCOUNT => 1},
                    'logger_facility'  => {ARGCOUNT => 1},
                    'http_host'        => {ARGCOUNT => ARGCOUNT_LIST},
                    'smtp_host'        => {ARGCOUNT => ARGCOUNT_LIST},
                    'imap_host'        => {ARGCOUNT => ARGCOUNT_LIST}
            );
     
            $conf -> file ('/etc/monitor/monitor.conf');
     
            # Mailer
            $mailer->{SMTP} = Net::SMTP -> new ($conf -> mailer_smtp ());
            $mailer->{SMTP} -> mail ($conf -> mailer_sender ());
            $mailer->{SMTP} -> to ($conf -> mailer_recipient ());
            $mailer->{SENDER} = $conf -> mailer_sender ();
            $mailer->{RECIPIENT} = $conf -> mailer_recipient ();
     
            # Logger
            $logger->{IDENT} = $conf -> logger_ident ();
            $logger->{LOGOPT} = '';
            $logger->{FACILITY} = $conf -> logger_facility ();
     
            # Cibles
            @$http_hosts = @{$conf -> http_host ()};
            @$smtp_hosts = @{$conf -> smtp_host ()};
            @$imap_hosts = @{$conf -> imap_host ()};
    }
    L'interpréteur considère que les variables n'ont pas été déclarées lors de l'appel de get_conf dans la procédure sig_hup.

  9. #9
    Membre du Club
    Inscrit en
    Octobre 2005
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 47
    Points : 56
    Points
    56
    Par défaut
    Je ne vois pas la cause du problème. En tout cas, ce n'est pas la référence, puisque les erreurs se produisent dans la déclaration de la fonction sig_hup, et non dans la définition de la référence.

    Donc, je persiste: il y a forcément un problème de scope qq part. Tu pourrais essayer de mettre les déclarations des variables dans un bloc autour de la déclaration de la fonction, du genre, pour être vraiment certain qu'elles sont visibles:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    {
       my ($mailer, $etc, $etc)
       get_conf(.....); 
       sub sig_hup  {
           get_conf( $mailer, $etc, $et, $compagnie);
       }
    }
    Aussi : pourquoi passer des arguments à get_conf(), puisqu'il s'agit de toute façon de les changer ?[/code]

  10. #10
    Yux
    Yux est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 105
    Points : 74
    Points
    74
    Par défaut
    Je vais tester ta solution. En ce qui concerne get_conf, elle initialise certaines variables à partir des paramètres contenus dans un fichier de configuration. Les variables concernées sont ensuites utilisées par d'autres fonctions. Je ne suis pas très versé en perl ni en programmation d'une manière générale, mais pour avoir touché un peu au C, je m'imaginais que la seule façon de modifier une variable "globale" dans le corps d'une fonction était d'effectuer un passage par adresse, comme en C. J'avais donc créé d'emblée des références anonymes sur des tableaux et des hachages plutôt que des variables standard. Je me dis que ça reste plus propre dans la mesure ou les variables ne sont pas copiées en mémoire lors de l'appel de procédures, mais je serais ravi d'avoir ton opinion sur la question. Si tu as un peu de temps et que le coeur t'en dis, je peux même balancer l'intégralité du code, histoire d'avoir un point de vue plus critique sur les choix effectués

  11. #11
    Membre du Club
    Inscrit en
    Octobre 2005
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 47
    Points : 56
    Points
    56
    Par défaut
    Tu étais sur la bonne piste. En somme, il y a deux techniques pour faire ce que tu veux. Soit simplement récupérer les valeurs que la fonction retoure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    my $val1;
    my $val2;
     
    ($val1, $val2) = my_sub();
     
    sub mysub {
         return "server", "autre donnée";
    }
    Soit on passe des références à la fonction, qui les modifie sans en faire une copie.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    my_sub( \$val1, \$val2);
     
    sub my_sub {
       $$val1 = 'server';
       $$val2 = "autre donnée";
    }
    Je veux bien regarder ton code (si ce n'est pas trop long ;-) mais c'est peut-être aussi bien que tu postes les parties qui te posent encore problème.

  12. #12
    Yux
    Yux est déconnecté
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 105
    Points : 74
    Points
    74
    Par défaut
    Euh, chostrama, je ne comprends pas trop ce que tu veux dire quand tu dis que j'étais sur la bonne piste ; j'ai fait exactement ce que tu montres dans cet exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    my_sub( \$val1, \$val2);
     
    sub my_sub {
       $$val1 = 'server';
       $$val2 = "autre donnée";
    }
    Dans mon cas, je transmets à la fonction get_conf 5 références anonymes, deux sur hachages et trois sur listes et d'ailleurs, ça marche très bien. Le problème se produit lorsque j'appelle get_conf au sein d'une autre fonction (sig_hup en l'occurence). Peut-être que lorsqu'elle est imbriquée, get_conf ne voit que ce qui a été défini dans le bloc supérieur (sig_hup), et pas les variables "globales" du programme.

  13. #13
    Membre du Club
    Inscrit en
    Octobre 2005
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 47
    Points : 56
    Points
    56
    Par défaut
    Désolé, j'avais mal regardé ton code. Tes déclarations sont dans un
    style un peu "C". (Je me demande, d'ailleurs, si tu gagnes quelque
    chose à utiliser des refs vers des hash/array anonymes. Ca complique
    un peu, car il faut sans cesse déréférencer.)

    Mais de toute façon, cela ne change toujours rien au problème. Les
    références sont visibles de la même manière que les scalaires normaux,
    car, du point de vue de perl, ce sont d'abord des scalaires, mais des
    scalaires qui renvoient à autre chose. Donc, ton code de test du début
    du thread reste parfaitement valable.

Discussions similaires

  1. [DOM] Fonctions "imbriquées" et valeur de retour
    Par hush dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 19/04/2007, 16h16
  2. Récupérer une fonction imbriquée
    Par Mikiman dans le forum Langage
    Réponses: 6
    Dernier message: 14/08/2006, 15h37
  3. Comportement fonctions imbriquées avec appel à Xmlhttprequest
    Par eirmag dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 04/05/2006, 16h10
  4. Fonctions imbriquées
    Par programaniac dans le forum Langage
    Réponses: 1
    Dernier message: 19/11/2005, 19h49
  5. Réponses: 10
    Dernier message: 03/03/2005, 13h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo