如何在Perl模块中创建私有函数?

时间:2009-01-16 18:51:04

标签: perl module perl-module private-functions

我正在研究一个小的Perl模块,出于某种原因,我有一个测试驱动程序脚本正在使用我的新模块调用我认为是私有的功能之一,并且它是成功的。我很惊讶,所以我开始搜索谷歌,我真的找不到任何关于如何在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模块中使用私有函数和变量?

感谢您帮助我学习!

9 个答案:

答案 0 :(得分:33)

来自perldoc perltoot(大约四分之一的文件):

  

Perl没有对谁使用哪种方法施加限制。该   公共与私人的区别是按惯例,而不是语法。 (好,   除非您使用下面“Data Members as”中描述的Alias模块   变量“。)偶尔你会看到方法名称的开头或结尾   一两个下划线。该标记是表示该标记的约定   方法仅对该类是私有的,有时是最接近的   熟人,它的直接子类。但这种区别是   不是由Perl本身强制执行的。这取决于程序员的行为。

因此,我建议您在“私人”方法的开头添加一个或两个下划线,以帮助阻止使用。

答案 1 :(得分:22)

只有“The Kludge”将代码引用存储在词法变量中,该范围之外的任何人都无法看到:

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

sub public_sub { 
    my $self = shift;

    $priv_func1->( $self );
}

我无法认为是一种制作严格“受保护”字段的方法。

据我所知(除了源代码过滤器......嘘。我没有提到它们......)


编辑:实际上,事实证明我可以想到一种非常混乱的保护方式。但它可能涉及通过AUTOLOAD子传递所有呼叫。 (!!)

答案 2 :(得分:14)

这有效:

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

sub public_sub { 
    my $self = shift;

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

答案 3 :(得分:8)

只需查看来电者:

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

答案 4 :(得分:6)

你想做什么?也许有更好的Perl方式来做你想要完成的任何事情。

例如,如果您不希望人们在您的对象中乱逛,因为您想要强制执行封装,则可以使用Class::InsideOut之类的内容。该模块有一个Class :: InsideOut :: About文档模块,解释了这个概念。还有Object::InsideOut,Brian Phillips已经提到过。

答案 5 :(得分:3)

当你意识到你不能只使用Data :: Dumper直接转储对象或窥视对象内部来查看其数据时,这种样式的OO会在一段时间后开始感觉有点“不完美”。但是,如果你想试一试,我建议使用Object::InsideOut。它支持对象的私有数据和方法,以及许多其他方便的功能(访问器生成,默认构造函数等)。

答案 6 :(得分:3)

我们可以在perl私有函数中写下面的一些内容来检查来自caller[0]的同一个obj的调用是否给了包。

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

答案 7 :(得分:2)

如果您使用Moose之类的系统,则可以看到公共/私人区别here

答案 8 :(得分:0)

在包的文件中:将私有方法定义为CODE-Ref,即:

my $private_methode = sub{};