/ / Як зробити приватні функції в модулі Perl? - perl, module, perl-module, private-functions

Як зробити приватні функції в модулі Perl? - perl, модуль, perl-модуль, private-функції

Я працюю над невеликим модулем Perl і для деякихтому у мене був сценарій тестового драйвера, який використовував мій новий модуль, викликав одну з функцій, які, на мою думку, були приватними, і він був успішним. Я був здивований, тому я почав шукати google, і я не міг дійсно знайти жодної документації про те, як зробити приватні функції в модулях Perl ...

Я бачив одне місце, де говорилося ставити крапку з комою після фінальної дужки вашої "приватної" функції, наприклад:

sub my_private_function {
...
};

Я спробував це, але мій сценарій драйвера все ще міг отримати доступ до функції, яку я хотів би бути приватною.

Я вигадаю щось, що буде коротшим прикладом, але ось що я після цього:

Модуль 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;
}

Драйвер: 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");

Вихід драйвера:

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!

Тож я додав крапку з комою після останньої фігурної фігурної дужки в модулі, але результат залишається незмінним. Єдине, що я дійсно знайшов, це додати цей рядок як перший рядок до моєї private_function:

caller eq __PACKAGE__ or die;

Але це здається досить удачним.У мене немає великого досвіду написання модулів Perl, тому, можливо, я неправильно налаштовую свій модуль? Чи можна мати приватні функції та змінні в модулях perl?

Дякую, що допомогли мені вчитися!

Відповіді:

33 для відповіді № 1

Від perldoc perltoot (приблизно чверть шляху до документа):

Perl не встановлює обмежень щодо того, хто потрапляєвикористовувати які методи. розрізнення державного та приватного є за домовленістю, а не синтаксисом. (Добре, якщо ви не використовуєте модуль Псевдонім, описаний нижче в "Члени даних як Змінні ".) Іноді ви побачите імена методів, що починаються або закінчуються на підкреслення або два. Це маркування є умовою, яка вказує на те, що методи приватні лише для цього класу, а іноді і для його найближчих знайомства, його безпосередні підкласи. Але ця відмінність є не виконується самою Perl. Програміст повинен поводитися.

Тому я рекомендую вам на початку "приватних" методів підкреслити або підкреслити, щоб запобігти використанню.


21 для відповіді № 2

Існує лише "The Kludge", в якому зберігається посилання на код у лексичній змінній, яку ніхто поза цим обсягом не бачить:

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

sub public_sub {
my $self = shift;

$priv_func1->( $self );
}

І я можу "т думай способу зробити суворо "захищені" поля.

Це, наскільки мені відомо (крім вихідних фільтрів ... тшшш. Я їх не згадував ....)


EDIT: Власне, виявляється я може придумайте дуже брудний спосіб робити захищений. Але це, мабуть, передбачало б передачу всіх дзвінків через AUTOLOAD під. (!!)


14 за відповідь № 3

Це працює:

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

sub public_sub {
my $self = shift;

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

8 для відповіді № 4

Просто перевірте абонента:

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

6 за відповідь № 5

Що ти намагаєшся робити? Можливо, є кращий спосіб Perl робити все, що ви намагаєтесь досягти.

Наприклад, якщо ви не хочете, щоб люди пограбували ваші об’єкти, тому що ви хочете забезпечити інкапсуляцію, ви можете використовувати щось на зразок Клас :: InsideOut. Цей модуль має Class :: InsideOut :: About модуль документації, який пояснює концепцію. Є також Об'єкт :: InsideOut, про яку вже згадував Брайан Філіпс.


3 для відповіді № 6

Цей стиль ОО починає відчуватися трохи"un-perlish" через деякий час, коли ви зрозумієте, що не можете просто використовувати Data :: Dumper, щоб скинути об'єкт безпосередньо або зазирнути всередину об'єкта, щоб переглянути його дані. Однак, якщо ви хочете спробувати, я " d рекомендую використовувати Об'єкт :: InsideOut. Він підтримує приватні дані та методи для ваших об'єктів, а також ряд інших зручних функцій (генерація доступу, конструктор за замовчуванням тощо).


3 для відповіді № 7

Ми можемо написати дещо нижче в приватній функції perl, щоб перевірити, чи дзвінок із того самого об'єкта, що і caller[0] дає пакет.

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

2 для відповіді № 8

Якщо ви використовуєте систему типу Мусь, ви можете отримати публічну / приватну різницю, як видно тут.


0 для відповіді № 9

У файлі для вашого пакета: Визначте приватні методи як CODE-Ref, тобто:

my $private_methode = sub{};