Domanda

Sto lavorando su un piccolo modulo Perl e per qualche motivo ho avuto lo script del driver di test che stava usando il mio nuovo modulo per chiamare una delle funzioni che pensavo fossero private ed è andata a buon fine. Sono rimasto sorpreso, quindi ho iniziato a cercare su Google e non sono riuscito a trovare alcuna documentazione su come creare funzioni private nei moduli Perl ...

Ho visto un posto che diceva di mettere un punto e virgola dopo la parentesi graffa di chiusura del tuo "privato" funzione, in questo modo:

sub my_private_function {
...
}; 

L'ho provato, ma il mio script del driver poteva ancora accedere alla funzione che volevo essere privata.

Tratterò qualcosa che sarà un esempio più breve, ma ecco cosa sto cercando:

Modulo 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;
}

Driver: 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");

Output del driver:

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!

Quindi ho aggiunto un punto e virgola dopo l'ultimo controvento di chiusura nel modulo, ma l'output è sempre lo stesso. L'unica cosa che ho davvero trovato è stata aggiungere questa riga come prima riga alla mia funzione_ privata:

caller eq __PACKAGE__ or die;

Ma sembra piuttosto confuso. Non ho molta esperienza nella scrittura di moduli Perl, quindi forse sto configurando il mio modulo in modo errato? È possibile avere funzioni e variabili private nei moduli perl?

Grazie per avermi aiutato a imparare!

È stato utile?

Soluzione

Da perldoc perltoot (circa un quarto del documento):

  

Perl non impone restrizioni su chi può usare quali metodi. Il   la distinzione tra pubblico e privato è per convenzione, non sintassi. (Bene,   a meno che tu non usi il modulo Alias ??descritto di seguito in " Data Members   Variabili " ;.) Occasionalmente vedrai i nomi dei metodi che iniziano o finiscono con   un trattino basso o due. Questa marcatura è una convenzione che indica che   i metodi sono privati ??solo per quella classe e talvolta per il più vicino   conoscenze, le sue sottoclassi immediate. Ma questa distinzione è   non applicato dallo stesso Perl. Spetta al programmatore comportarsi.

Pertanto, ti consiglio di inserire un trattino basso o due all'inizio del tuo "privato" metodi per dissuadere l'utilizzo.

Altri suggerimenti

Esiste solo " The Kludge " di memorizzare un riferimento di codice in una variabile lessicale, che nessuno al di fuori di tale ambito può vedere:

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

sub public_sub { 
    my $self = shift;

    $priv_func1->( $self );
}

E non riesco a pensare un modo per rendere rigorosamente "protetto" campi.

Per quanto ne so (oltre ai filtri sorgente ... shhhh. Non li ho menzionati ....)


MODIFICA: In realtà, risulta che posso pensare a un modo molto disordinato di proteggere. Ma probabilmente comporterebbe il passaggio di tutte le chiamate attraverso il AUTOLOAD . (!!)

Funziona:

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

sub public_sub { 
    my $self = shift;

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

Controlla solo il chiamante:

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( );

Cosa stai cercando di fare? Forse esiste un modo Perl migliore di fare qualunque cosa tu stia cercando di realizzare.

Ad esempio, se non vuoi che le persone si confondano nei tuoi oggetti perché vuoi imporre l'incapsulamento, puoi usare qualcosa come Class :: InsideOut . Quel modulo ha un modulo di documentazione Class :: InsideOut :: About che spiega il concetto. Esiste anche Object :: InsideOut , di cui Brian Phillips ha già parlato.

Questo stile di OO inizia a sembrare un po '"non-perlish" dopo un po 'quando ti rendi conto che non puoi semplicemente usare Data :: Dumper per scaricare direttamente l'oggetto o sbirciare dentro l'oggetto per vedere i suoi dati. Tuttavia, se vuoi provarlo, ti consiglio di utilizzare Object :: InsideOut . Supporta dati e metodi privati ??per i tuoi oggetti insieme a una serie di altre utili funzionalità (generazione di accessori, costruttore predefinito, ecc.)

Possiamo scrivere qualcosa sotto nella funzione privata perl per verificare se la chiamata dallo stesso oggetto di caller [0] dà il pacchetto.

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

Se usi un sistema come Moose , puoi ottenere una distinzione pubblica / privata come visto qui .

In File per il pacchetto: definire i metodi privati ??come CODE-Ref, ovvero:

my $private_methode = sub{};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top