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.