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 :

Les références en Perl - ou - mes débuts en POO : le constructeur :)


Sujet :

Langage Perl

  1. #1
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut Les références en Perl - ou - mes débuts en POO : le constructeur :)
    Hello tout le monde,

    voilà, je commence à m'intéresser un peu à la POO en Perl, et, bien que je sache que les développeurs Perl travaillent toujours proprement, et qu'on a pas besoin de garde fous je voulais, pour ma culture personnelle, développer un peu le fonctionnement des constructeurs... et par extension, des références en Perl d'ailleurs.

    En gros, l'idée est la suivante: grâce aux supers cours/FAQ de ce même site (merci encore à tous les auteurs de la FAQ et des cours que je ne nommerai pas car j'en oublierai sûrement), j'ai commencé à faire une petite classe basique. Pour le constructeur, je passe en paramètre une référence anonyme à une table de hashage contenant les attributs (j'espère avoir le bon vocabulaire =).

    Pour le moment, j'avais 2 attributs :
    1. un scalaire
    2. une table de hashage dont je passe la référence


    Mon "problème", c'est que je voulais pouvoir "recopier" la table de hashage pour éviter de travailler sur la version passée en paramètre. J'ai une solution en utilisant une table temporaire, mais je voulais savoir s'il n'y avait pas quelque chose de plus propre...

    Exemple:
    test.pl
    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
     
    use strict;
    use warnings;
    use Data::Dumper;
     
    use Server;
     
    my $cfg_ip='1.2.3.4';
    my %cfg_users=( toto => 'titi' );
     
    my $server = Server->new( {	ip => $cfg_ip,
    				ref_users => \%cfg_users
    			} );
     
    print $server->to_string();
     
    print Dumper(\%cfg_users);
    print $cfg_ip;
    Server.pm
    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
    # --- fichier Server.pm ---
    package Server;
    use strict;
    use warnings;
    use Carp;
     
    # constructeur:
    #  1. nom de la classe (passe automatiquement)
    #  2. adresse ip du serveur
    #  3. tableau de hachage user => mdp
    sub new {
    	my ($classe, $ref_args) = @_;
     
    	# Vérification de la classe
    	$classe = ref($classe) || $classe;
     
    	# Vérification des champs nom, prenom et sexe
    	foreach my $attribut (qw/ ip ref_users /) {
    		croak ("[WARN] Attribut $attribut manquant") unless ( defined $ref_args->{$attribut} );
    	}
     
    	# Création de la référence anonyme de hachage vide (futur objet)
    	my $this = {};
     
    	# Liaison de l'objet à la classe
    	bless ($this, $classe);
     
    	$this->{_IP}	= $ref_args->{ip};
    	$this->{_USERS}	= $ref_args->{ref_users};
     
    	# test modif valeurs pour la portée
    	$this->{_IP} = '4.3.2.1';
    	$this->{_USERS}->{toto} = 'tutu';
     
    	return $this;
    }
     
    # to_string:
    sub to_string {
    	my $this = shift;
     
    	print "$this->{_IP} :\n";
     
    	foreach (sort keys %{$this->{_USERS}}) {
    		printf ("%10s\t%10s\n", $_, $this->{_USERS}->{$_});
    	}
    }
     
    1;
    Exécution
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    D:\50-Travail>perl test.pl
    4.3.2.1 :
          toto            tutu
    $VAR1 = {
              'toto' => 'tutu'
            };
    1.2.3.4
    Bon, on voit bien que si je modifie les valeurs dans la classe, l'adresse ip du programme test.pl n'est pas modifiée (normal, je copie la valeur), alors que la hashtable des utilisateurs est modifiée car je passe par une référence... jusque là, ok !

    Maintenant, je souhaitais "protéger" la hashtable en entrée pour éviter ce genre de problème. Je n'ai trouvé qu'une solution, remplacer dans le constructeur ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	$this->{_USERS}	= $ref_args->{ref_users};
    par cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	my %tmp_users = %{$ref_args->{ref_users}};
    	$this->{_USERS}	= \%tmp_users;
    Alors ça marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    D:\50-Travail>perl test.pl
    4.3.2.1 :
          toto            tutu
    $VAR1 = {
              'toto' => 'titi'
            };
    1.2.3.4
    mais je trouve pas ça beau

    Un indice ?!

    Merci d'avance.

  2. #2
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Tu as trouvé tout seul la solution. C'est en effet le problème en Perl POO. La protection des attributs ne dépends que de la bonne pratique du développeur.

    Si tu procèdes comme tu l'as fait, ce n'est peut être pas beau encore que ce n'est pas choquant. Le seul souci est peut être que ça nécessite de prendre un peu plus de mémoire.

    Mais tu peux par la suite utiliser des techniques plus avancées comme cela est expliqué dans l'article via l'utilisation d'autres modules. Et là, tu ne te posera plus la question

    Bonne apprentissage

  3. #3
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    mmmh, ok, merci pour l'info

    J'irais voir du côté de Coat quand même si je veux pousser un peu... parce que j'ai un autre trucs qui me chiffonne et pour lequel je ne vois pas de contournement simple : le contrôle des variables passées au constructeur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    my $server = Server->new( {	ip => $cfg_ip,
    				ref_users => \%cfg_users
    			} );
    Si le mec se plante en passant un tableau au lieu d'un scalaire, ou au lieu du hashref ou n'importe quoi, ça fout un peu tout en l'air, et ça me semble complexe à contrôler !

  4. #4
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Non, moi je ne parle pas de Coat. Je te recommande Object::InsideOut.
    Avec Coat ou Moose, c'est sûr que l'écriture est propre, tu peux faire tout tes contrôles. La POO est un peu plus simple. Le seul inconvénient et la protection de l'encapsulation. Mais avec Object::InsideOut, Il est impossible de trifouiller l'objet. Tout est dans l'article.

  5. #5
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    Erf, j'avais décider de faire un pause après le paragraphe C de ton tutorial (excellent soit dit en passant, j'espère arriver un jour à maîtriser autant ce langage !)... je commençais à fatiguer pour la suite ;o)

    Bon, j'y retourne !!

  6. #6
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Citation Envoyé par Alek-C Voir le message
    Erf, j'avais décider de faire un pause après le paragraphe C de ton tutorial (excellent soit dit en passant, j'espère arriver un jour à maîtriser autant ce langage !)... je commençais à fatiguer pour la suite ;o)

    Bon, j'y retourne !!


    N'hésite pas à laisser un commentaire ici.

  7. #7
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Tu peux contrôler le type des paramètres à l'aide de la fonction ref (perldoc -f ref).

  8. #8
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Tu peux contrôler le type des paramètres à l'aide de la fonction ref (perldoc -f ref).
    C'est sûr. C'est d'ailleurs ce que font les modules en question. Mais je suppute qu'il connaissait déjà cette commende, quoi que !

  9. #9
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    Oui, je connaissais... mais sauf erreur, ça a vite des limites !

    D'ailleurs, ObjectInsideOut, même s'il est très amusant à utiliser et très performant, ne résout pas mon "problème".

    Je m'explique à nouveau avec mes zolis exemples
    test.pl (identique pour les 2 classes Server.pm et Server_1.pm: seul le "use" change dans le code ci-dessous suivant le test souhaité):
    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
    #!/usr/bin/perl
     
    use strict;
    use warnings;
    use Data::Dumper;
     
    use Server;
     
    my $cfg_ip='1.2.3.4';
    my @cfg_ip=($cfg_ip, 'ip', 'truc');
    my %cfg_users=( toto => 'titi' , tutu => 'tata');
     
    my $server = Server->new( {	ip => @cfg_ip,
    				ref_users => \%cfg_users
    			} );
     
    print $server->get_ip(),"\n";
    my @usernames = $server->get_users();
    foreach (@usernames) {
    	print "$_ : ",$server->get_password($_),"\n";
    }
    Ma première classe Server.pm associée:
    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
    # --- fichier Server.pm ---
    package Server;
    	{
    	use strict;
    	use warnings;
    	use Carp;
     
    	use vars qw($VERSION);
    	$VERSION='2.0';
     
    	use Object::InsideOut;
     
    	my @ip :Field
    	   :Get(get_ip)
    	   :Arg('Name' => 'ip', 'Mandatory' => 1)
    	   :Type('Scalar')
    	   ;
     
    	my @ref_users :Field
    		  :Get(users_list)
    		  :Arg('Name' => 'ref_users', 'Mandatory' => 1)
    		  :Type('HASH')
    		  ;
     
    	# get_users:
    	#  retourne une liste des utilisateurs
    	sub get_users {
    		my $self = shift;
    		return (keys %{$ref_users[$$self]});
    	}
     
    	# get_password:
    	#  retourne le mot de passe d'un utilisateur
    	sub get_password {
    		my ($self, $username) = @_;
    		return (exists $self->users_list->{$username}) ? $self->users_list->{$username} : undef;
    	}
    }
    1;
    __END__
    Server_1.pm (classe classique):
    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
    60
    61
    62
    63
    64
    65
    # --- fichier Server.pm ---
    package Server;
    use strict;
    use warnings;
    use Carp;
     
    use vars qw($VERSION);
    $VERSION='2.0';
     
    my %attributs_types = (	ip => 'SCALAR',
    		ref_users	=> 'REFHASH');
    # constructeur:
    #  1. nom de la classe (passe automatiquement)
    #  2. adresse ip du serveur
    #  3. tableau de hachage user => mdp
    sub new {
    	my ($classe, $ref_args) = @_;
     
    	# Vérification de la classe
    	$classe = ref($classe) || $classe;
    	print Dumper($ref_args);
    	# Vérification des champs nom, prenom et sexe
    	foreach my $attribut (qw/ ip ref_users /) {
    		my $type = $attributs_types{$attribut};
    		croak ("[WARN] Attribut $attribut manquant") unless ( defined $ref_args->{$attribut} );
    		croak ("[WARN] Attribut $attribut doit etre un ".$type)
    			unless ( $type =~ /^REF/ ? ref($ref_args->{$attribut}) : ref(\$ref_args->{$attribut}) eq $type );
    	}
     
    	# Création de la référence anonyme de hachage vide (futur objet)
    	my $this = {};
     
    	# Liaison de l'objet à la classe
    	bless ($this, $classe);
     
    	$this->{_IP}	= $ref_args->{ip};
    	my %tmp_users = %{$ref_args->{ref_users}};
    	$this->{_USERS} = \%tmp_users;
     
    	return $this;
    }
     
    # get_ip:
    #  retourne l'adresse ip du serveur
    sub get_ip {
    	my $this = shift;
    	return $this->{_IP};
    }
     
    # get_users:
    #  retourne une liste des utilisateurs
    sub get_users {
    	my $this = shift;
    	return keys %{$this->{_USERS}};
    }
     
    # get_password:
    #  retourne le mot de passe d'un utilisateur
    sub get_password {
    	my ($this, $username) = @_;
    	return (exists $this->{_USERS}->{$username}) ? $this->{_USERS}->{$username} : undef;
    }
     
    1;
    __END__
    Bon, ça n'est pas nécessaire de lire tout le code je pense, mais même si je reconnais que c'est un peu tiré par les cheveux, ça montre que pour le moment, je ne suis pas capable de faire un test important sur mes données en entrées (je n'ai qu'à bien coder !).

    Résultat de perl test.pl:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >perl test.pl
    truc
    toto : titi
    tutu : tata

  10. #10
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Voici ton code réindenté avec une petite modif dans server.pm. Mais en faite, quel est ton problème ?

    test.pl
    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
    #!/usr/bin/perl
    use strict;
    use warnings;
     
    use Server;
     
    my $cfg_ip    = '1.2.3.4';
    my @cfg_ip    = ( $cfg_ip, 'ip', 'truc' );
    my %cfg_users = ( toto => 'titi', tutu => 'tata' );
     
    my $server = Server->new(
      { ip        => @cfg_ip,
        ref_users => \%cfg_users
      }
    );
     
    print $server->get_ip(), "\n";
    my @usernames = $server->get_users();
    foreach (@usernames) {
      print "$_ : ", $server->get_password($_), "\n";
    }
    Server.pm
    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
    # --- fichier Server.pm ---
    package Server;
    {
      use strict;
      use warnings;
      use Carp;
     
      use vars qw($VERSION);
      $VERSION = '2.0';
     
      use Object::InsideOut;
     
      my @ip : Field : Get(get_ip) : Arg('Name' => 'ip', 'Mandatory' => 1) : Type('Scalar');
     
      my @ref_users : Field : Get(users_list) : Arg('Name' => 'ref_users', 'Mandatory' => 1) : Type('HASH');
     
      # get_users:
      #  retourne une liste des utilisateurs
      sub get_users {
        my $self = shift;
        return ( keys %{ $self->users_list } );
      }
     
      # get_password:
      #  retourne le mot de passe d'un utilisateur
      sub get_password {
        my ( $self, $username ) = @_;
        return ( exists $self->users_list->{$username} ) ? $self->users_list->{$username} : undef;
      }
    }
    1;
    Server1.pm
    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
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    # --- fichier Server.pm ---
    package Server1;
    use strict;
    use warnings;
    use Carp;
    use Data::Dumper;
     
    use vars qw($VERSION);
    $VERSION = '2.0';
     
    my %attributs_types = (
      ip        => 'SCALAR',
      ref_users => 'REFHASH',
    );
     
    # constructeur:
    #  1. nom de la classe (passe automatiquement)
    #  2. adresse ip du serveur
    #  3. tableau de hachage user => mdp
    sub new {
      my ( $classe, $ref_args ) = @_;
     
      # Vérification de la classe
      $classe = ref($classe) || $classe;
      print Dumper($ref_args);
     
      # Vérification des champs nom, prenom et sexe
      foreach my $attribut (qw/ ip ref_users /) {
        my $type = $attributs_types{$attribut};
        croak("[WARN] Attribut $attribut manquant") unless ( defined $ref_args->{$attribut} );
        croak( "[WARN] Attribut $attribut doit etre un " . $type )
          unless ( $type =~ /^REF/ ? ref( $ref_args->{$attribut} ) : ref( \$ref_args->{$attribut} ) eq $type );
      }
     
      # Création de la référence anonyme de hachage vide (futur objet)
      my $this = {};
     
      # Liaison de l'objet à la classe
      bless( $this, $classe );
     
      $this->{_IP} = $ref_args->{ip};
      my %tmp_users = %{ $ref_args->{ref_users} };
      $this->{_USERS} = \%tmp_users;
     
      return $this;
    }
     
    # get_ip:
    #  retourne l'adresse ip du serveur
    sub get_ip {
      my $this = shift;
      return $this->{_IP};
    }
     
    # get_users:
    #  retourne une liste des utilisateurs
    sub get_users {
      my $this = shift;
      return keys %{ $this->{_USERS} };
    }
     
    # get_password:
    #  retourne le mot de passe d'un utilisateur
    sub get_password {
      my ( $this, $username ) = @_;
      return ( exists $this->{_USERS}->{$username} ) ? $this->{_USERS}->{$username} : undef;
    }
     
    1;
    __END__

  11. #11
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    Lol !

    Bon, déjà, merci pour la modif

    Ensuite, je n'ai pas vraiment dit que j'avais un problème

    Enfin, si, j'ai parlé de problème, mais entre guillemets parce que ça n'en est pas vraiment un, plutôt une préoccupation...

    Comme je le disais un peu plus, haut, c'est la façon dont les variables sont passées au constructeur des classes en Perl qui me gêne car il n'y a au final que très peu de contrôles possibles.

    Dans les exemples que tu as recopié, j'ai, dans mon main.pl, 2 variables cfg_ip: une scalaire et un tableau.
    Normalement, j'attends un variable scalaire pour l'attribut ip dans mon constructeur.
    Mais si le développeur fait n'importe quoi (sans pour autant devenir n'importe qui), on peut arriver à des résultats bizarres à cause de la mise à plat que Perl fait dans les listes.

    Dans l'exemple que tu cites, on a ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    my @cfg_ip    = ( $cfg_ip, 'ip', 'truc' );
    my %cfg_users = ( toto => 'titi', tutu => 'tata' );
     
    my $server = Server->new(
      { ip        => @cfg_ip,
        ref_users => \%cfg_users
      }
    );
    On voit bien dans le résultat, que la valeur de l'attribut ip de ma classe vaut 'truc' au lieu de 1.2.3.4 (s'il avait passé $cfg_ip, ou même pris le premier argument du tablea @cfg_ip).
    L'attribut ip est en effet positionné par le troisième élément du tableau passé par erreur en paramètre du constructeur et qui suit (manque de pot), le mot 'ip' en seconde position... Si le tableau était pair, on aurait une erreur à l'exécution.
    En fait, ma table de hashage anonyme devient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      { ip        => ('1.2.3.4' , 'ip', 'truc' ),
        ref_users => \%cfg_users
      }
    soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      { ip        => '1.2.3.4',
        'ip' => 'truc',
        ref_users => \%cfg_users
      }
    soit encore (le second 'ip' squizzant le premier)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      { 'ip' => 'truc',
        ref_users => \%cfg_users
      }
    Bref, comme je l'ai dit, c'est un peu tiré par les cheveux, mais, c'était juste ce point qui me perturbait. J'aurais aimé pouvoir lever une erreur si on passe un tableau au lieu d'un scalaire dans le constructeur, mais comme c'est Perl qui aplatit le tout, j'imagine que ce n'est pas possible ?

  12. #12
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Bon, là je ne suis pas d'accord avec toi. Le problème est ton code et tes vérifications.

    Dans ton .pl tu fais ceci,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    my $server = Server->new(
      { ip        => @cfg_ip,
        ref_users => \%cfg_users
      }
    );
    Donc tu t'attends à ce que ip soit un tableau (ce qui n'est déjà pas propre, car la meilleure façon aurait été de mettre la référence au tableau).
    De plus, Cette écriture est erronée. Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    my @cfg_ip    = ( $cfg_ip, 'ip', 'truc' );
    my %cfg_users = ( toto => 'titi', tutu => 'tata' );
    my $tutu = { 
      ip        => @cfg_ip,
      ref_users => \%cfg_users
    };
    print Dumper $tutu;
    te donnera
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $VAR1 = {
              'ip' => 'truc',
              'ref_users' => {
                               'toto' => 'titi',
                               'tutu' => 'tata'
                             }
            };
    Donc tu peux déjà constater que la valeur de ip n'est pas un tableau, mais un scalaire, ce qui est déjà erroné pas rapport à tes attentes.

    Dans ton .pm, tu fais ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      my @ip : Field : Get(get_ip) : Arg('Name' => 'ip', 'Mandatory' => 1) : Type('Scalar');
    Donc, ce n'est déjà pas logique, le type Scalar attend tout sauf une référence, donc dans ton cas, ne vérifie rien.

    La façon la plus propre est de passer une référence de tableau.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    my $server = Server->new(
      { ip        => \@cfg_ip,
        ref_users => \%cfg_users
      }
    );
    et dans le .pm
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      my @ip : Field : Get(get_ip) : Arg('Name' => 'ip', 'Mandatory' => 1) : Type('ARRAY_ref');
    et ton résultat sera ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ARRAY(0x1830440)
    toto : titi
    tutu : tata
    Si tu t'hazardes maintenant à écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    { 'ip' => 'truc',
        ref_users => \%cfg_users
      }
    Tu auras un gentil message du type :
    OIO::Args error: Bad value for initializer 'ip': truc
    Usage: Initializer 'ip' for class 'Server' must be an object or ref of type 'ARRAY'
    Package: main
    File: xxxxx\test.pl
    Line: 12


    Trace begun at xxxxx\test.pl line 12
    Documentation sur les vérifications

  13. #13
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut


    C'est exactement ce que je ne veux pas faire, j'ai du mal m'expliquer.

    Je veux avoir un scalaire passé en paramètre de mon constructeur (en plus du hashref).

    MAIS si un programmateur ne fais pas gaffe, et passe un tableau au lieu du scalaire, je ne vois pas comment l'empêcher ou même le détecter car selon moi, Perl va mettre à plat la table de hashage anonyme à l'appel du constructeur, et une fois dans la classe, je ne verrai jamais qu'il y avait en fait une liste passée avec un paramètre qui s'est fait écraser.

    Je ne veux absolument pas passer un tableau, mais je voudrais pouvoir détecter qu'un programmateur fais ce que tu as fais (et qui n'est pas propre comme tu le dis si bien ). C'est ce que j'ai mis dans la suite de mon post avec les transformations successives de la table de hashage anonyme !

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Il y avait bien l'usage des prototypes, mais cette technique a été abandonnée, n'est-ce pas ?

  15. #15
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    oui mais les prototypes ne sont pas fait pour ce genre d'usage.
    La question est comment gérer cette exemple ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/perl
    use strict;
    use warnings;
    use Data::Dumper;
    my @cfg_ip    = ( $cfg_ip, 'ip', 'truc' );
    my %cfg_users = ( toto => 'titi', tutu => 'tata' );
    my $tutu = { 
      ip        => @cfg_ip,
      ref_users => \%cfg_users
    };
    print Dumper $tutu;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $VAR1 = {
              'ip' => 'truc',
              'ref_users' => {
                               'toto' => 'titi',
                               'tutu' => 'tata'
                             }
            };
    Pourquoi on obtient 'ip' => 'truc',

  16. #16
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Parce que @cfg_ip est interprété comme une liste et non un tableau. Il prend alors le dernier élément de la liste (opérateur ,) en plus de la clé ip, ce qui donne ip => truc.

    C'est mon interprétation, elle est peut-être fausse.

  17. #17
    Membre chevronné

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Points : 1 894
    Points
    1 894
    Par défaut
    Ben ça vient tout bêtement de la mise à plat de la liste par Perl...

    Quand tu fais un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( ( 1 , 2 ) , ( 2 , 4 ) )
    Perl aplatit la liste :
    Ici, le problème, c'est qu'on a une hashtable, donc une seule clé possible, donc la dernière valeur de la clé ip remplace la première:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( ip => ( 1 , ip , 2 ) , ref_users => \%cfg_users )
    Equivalent à (une hashtable étant plus ou moins une liste je crois) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( ip, ( 1 , ip , 2 ) , ref_users , \%cfg_users )
    Equivalent à (mise à plat) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( ip, 1 , ip , 2 , ref_users , \%cfg_users )
    Equivalent à (liste => hashtable) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( ip => 1 , ip => 2 , ref_users => \%cfg_users )
    Qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( ip => 2 , ref_users => \%cfg_users )
    Tout comme ceci au final:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    my %test;
    $test{ip} = 1;
    $test{ip} = 2;
    $test{ref_users} = \%cfg_users;
    J'aurais aimé pouvoir le contrôler, mais je pense que ça n'est pas possible car c'est un fonctionnement de Perl =)

    Bref, c'est pas très grave hein, j'espère que vous ne penchez pas dessus

  18. #18
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Bonne explication .
    De toute façon, tu ne peux pas tout gérer. Chaque langage a son mode de fonctionnement et la grande difficulté dans le debuggage est la recherche d'erreurs ne générant pas d'erreurs . Et là c'est un bon exemple.

  19. #19
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Bien joué Alek... j'avais bien un doute sur mon explication, mais la tienne me semble parfaite.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL-2003] lister les références actives de mes classeurs
    Par Henri-gp dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 12/03/2012, 10h39
  2. [PHP 5.0] Mes débuts en POO
    Par dpmix dans le forum Langage
    Réponses: 18
    Dernier message: 15/01/2010, 10h49
  3. Mes débuts en Perl, un peu d'aide svp
    Par Kiyoshi dans le forum Langage
    Réponses: 7
    Dernier message: 22/09/2008, 10h43
  4. Pb avec les références d'une base de données
    Par Celia1303 dans le forum Access
    Réponses: 8
    Dernier message: 01/12/2005, 15h44
  5. Problème avec les boutons de perl Tk
    Par jkevin2 dans le forum Interfaces Graphiques
    Réponses: 4
    Dernier message: 02/09/2005, 17h18

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