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

5rgfhyps  于 2022-11-15  发布在  Perl
关注(0)|答案(9)|浏览(152)

我正在开发一个小Perl模块,由于某种原因,我让测试驱动脚本使用我的新模块调用了一个我认为是私有的函数,它成功了。我很惊讶,所以我开始搜索谷歌,我真的找不到任何关于如何在Perl模块中创建私有函数的文档...
我看到有一个地方说要在“private”函数的右大括号后面放一个分号,就像这样:

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模块中有没有可能有私有函数和变量?
谢谢你帮我学习!

798qvoo8

798qvoo81#

perldoc perltoot开始(大约文档的四分之一):
Perl并不限制谁可以使用哪种方法,public与private的区别是根据惯例而不是语法。(好吧,除非您使用“作为变量的数据成员”中介绍的Alias模块。)有时您会看到方法名以一条或两条下划线开头或结尾。这种标记是一种约定,表示方法只对该类私有,有时也对它最亲近的人私有,它的直接子类。但是Perl本身并不强制执行这种区分。这取决于程序员的行为。
因此,我建议您在“private”方法的开头加上一两个下划线,以避免使用。

r3i60tvu

r3i60tvu2#

只有在词法变量中存储代码引用的“Kludge”,该作用域之外的任何人都看不到:

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

sub public_sub { 
    my $self = shift;

    $priv_func1->( $self );
}

我也想不出一种方法来严格地“保护”字段。
据我所知就是这样(除了源过滤器...嘘。我没有提到它们...)

**编辑:**事实上,我 * 能 * 想到一种非常混乱的保护方式。但它可能涉及通过AUTOLOAD sub传递所有调用。(!!)

tmb3ates

tmb3ates3#

这是可行的:

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

sub public_sub { 
    my $self = shift;

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

t1qtbnec4#

刚查来电人:

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

zhte4eai5#

你想做什么?也许有一个更好的Perl方法来做你想完成的事情。
例如,如果你不想让人因为你想强制封装而在你的对象中捣乱,你可以使用类似Class::InsideOut的东西。这个模块有一个Class::InsideOut::About文档模块来解释这个概念。还有一个Object::InsideOut,Brian菲利普斯已经提到过。

qfe3c7zg

qfe3c7zg6#

当您意识到不能直接使用Data::Dumper转储对象或查看对象内部的数据时,这种OO风格开始有点“不完美”。但是,如果您想给予一下,我建议使用Object::InsideOut。它支持对象的私有数据和方法沿着许多其他方便的特性(访问器生成、默认构造函数等)。

xdnvmnnf

xdnvmnnf7#

我们可以在下面的perl私有函数中写一些东西来检查来自caller[0]的同一个对象的调用是否给出包。

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

gcxthw6b8#

如果您使用Moose这样的系统,您可以获得如here所示的public/private区别。

6ju8rftf

6ju8rftf9#

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

my $private_methode = sub{};

相关问题