38 votes

Comment créer des fonctions privées dans un module Perl?

Je suis en train de travailler sur un petit module Perl et pour une raison que j'ai eu le pilote d'essai de script qui a été à l'aide de mon nouveau module appeler une des fonctions que j'ai pensé que cela pourrait être privé, et il a réussi. J'ai été surpris, j'ai donc commencé à chercher sur google et je ne pouvais pas vraiment trouver toute la documentation sur la façon de faire les fonctions privées dans les modules Perl...

J'ai vu un endroit qui a dit de mettre un point-virgule après l'accolade de fermeture de votre "privé" de la fonction, comme ceci:

sub my_private_function {
...
};

J'ai essayé, mais mon chauffeur script peut encore accéder à la fonction que je voulais être privé.

Je vais faire quelque chose qui sera plus courte, par exemple, mais voici ce que je suis après:

Module TestPrivate.pm:

package TestPrivate;

require 5.004;

use strict;
use warnings;
use Carp;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

require Exporter;

@ISA = qw(Exporter AutoLoader);

our @EXPORT_OK = qw( public_function );
our @EXPORT    = qw( );

$VERSION = '0.01';

sub new {
    my ( $class, %args ) = @_;
    my $self = {};
    bless( $self, $class );
    $self->private_function("THIS SHOULD BE PRIVATE");
    $self->{public_variable} = "This is public";
    return $self;
}

sub public_function {
    my $self     = shift;
    my $new_text = shift;
    $self->{public_variable} = $new_text;
    print "Public Variable: $self->{public_variable}\n";
    print "Internal Variable: $self->{internal_variable}\n";
}

sub private_function {
    my $self     = shift;
    my $new_text = shift;
    $self->{internal_variable} = $new_text;
}

Pilote: TestPrivateDriver.pl

#!/usr/bin/perl
use strict;
use TestPrivate 'public_function';
my $foo = new TestPrivate();
$foo->public_function("Changed public variable");
$foo->private_function("I changed your private variable");
$foo->public_function("Changed public variable again");
$foo->{internal_variable} = "Yep, I changed your private variable again!";
$foo->public_function("Changed public variable the last time");

Pilote de sortie:

Public Variable: Changed public variable
Internal Variable: THIS SHOULD BE PRIVATE
Public Variable: Changed public variable again
Internal Variable: I changed your private variable
Public Variable: Changed public variable the last time
Internal Variable: Yep, I changed your private variable again!

J'ai donc ajouté un point-virgule après la dernière accolade fermante dans le module, mais le résultat est toujours le même. La seule chose que j'ai vraiment trouvé a été d'ajouter cette ligne à la première ligne de mon private_function:

caller eq __PACKAGE__ or die;

Mais qui semble assez hacky. Je n'ai pas beaucoup d'expérience dans l'écriture de modules Perl, donc peut-être que je suis en train de mon module de mal? Est-il possible d'avoir privé de variables et de fonctions dans les modules perl?

Merci de m'aider à apprendre!

39voto

jedihawk Points 321

D' perldoc perltoot (environ un quart de chemin à travers le document):

Perl n'impose pas de restrictions sur qui peut utiliser les méthodes. L' public versus privé distinction est, par convention, de ne pas la syntaxe. (Eh bien, sauf si vous utilisez l'Alias module décrit ci-dessous dans "Données Membres Les Variables".) Occasionnellement, vous trouverez les noms de méthode en début ou de fin avec un trait de soulignement ou deux. Ce marquage est une convention indiquant que le les méthodes sont privés de la classe, seul, et parfois les plus proches connaissances, ses immédiate des sous-classes. Mais cette distinction est non imposé par Perl lui-même. C'est au programmeur de se comporter.

Par conséquent, je vous recommande de mettre un trait de soulignement ou deux au début de votre "privé" des méthodes pour aider à dissuader l'utilisation.

24voto

Axeman Points 24103

Il y a seulement "La Bidouille" de stockage d'un code de référence dans une variable lexicale qui n'en dehors de cette portée peut voir:

my $priv_func1 = sub { my $self = shift; say 'func1'; };

sub public_sub { 
    my $self = shift;

    $priv_func1->( $self );
}

Et je ne peux pas penser à une façon de faire rigoureusement "protégé" des champs.

Ça y est, autant que je sache ( en plus de la source de filtres...chut. Je n'en parle pas.... )


EDIT: en Fait, il s'avère que je peux penser à un très salissant façon de faire protégées. Mais il faudrait probablement passer tous les appels par le biais de l' AUTOLOAD sous. (!!)

15voto

Leon Timmermans Points 23230

Cela marche:

 my $priv_func1 = sub {
    my $self = shift; say 'func1';
};

sub public_sub { 
    my $self = shift;

    $self->$priv_func1(@_);
}
 

9voto

JDrago Points 1479

Vérifiez simplement l'appelant:

 package My;

sub new {
  return bless { }, shift;
}

sub private_func {
  my ($s, %args) = @_;
  die "Error: Private method called"
    unless (caller)[0]->isa( ref($s) );

  warn "OK: Private method called by " . (caller)[0];
}

sub public_func {
  my ($s, %args) = @_;

  $s->private_func();
}

package main;

my $obj = My->new();

# This will succeed:
$obj->public_func( );

# This will fail:
$obj->private_func( );
 

6voto

brian d foy Points 71781

Qu'essayez-vous de faire? Peut-être il ya une meilleure Perl façon de faire ce que vous essayez d'accomplir.

Par exemple, si vous ne voulez pas que les gens de déblayage autour de vos objets parce que vous voulez vous faire respecter l'encapsulation, vous pouvez utiliser quelque chose comme Classe::InsideOut. Ce module dispose d'une Classe::InsideOut::à Propos du module de documentation qui explique le concept. Il est également l'Objet::InsideOut, qui Brian Phillips déjà mentionné.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X