我正在研究一个小的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模块中使用私有函数和变量?
谢谢你帮我学习!
从perldoc perltoot
(大约四分之一的文件):
Perl没有对谁使用哪种方法施加限制.公共与私人的区别是按惯例,而不是语法.(好吧,除非您使用下面"数据成员作为变量"中描述的Alias模块.)有时您会看到以下划线或下划线开头或结尾的方法名称.此标记是一种约定,表示方法仅对该类是私有的,有时对其最近的熟人(其直接子类)是私有的.但Perl本身并没有强制执行这种区分.这取决于程序员的行为.
因此,我建议您在"私人"方法的开头加上一个或两个下划线,以帮助阻止使用.
只有"The Kludge"将代码引用存储在词法变量中,该范围之外的任何人都看不到:
my $priv_func1 = sub { my $self = shift; say 'func1'; }; sub public_sub { my $self = shift; $priv_func1->( $self ); }
而且我想不出一种方法来制造严格的"受保护"字段.
就我所知,这就是它(除了源代码过滤器......嘘.我没有提到它们......)
编辑:事实上,事实证明,我可以想到一个非常混乱的做保护方式.但它可能涉及通过AUTOLOAD
子传递所有呼叫.(!!)
这有效:
my $priv_func1 = sub { my $self = shift; say 'func1'; }; sub public_sub { my $self = shift; $self->$priv_func1(@_); }
只需检查来电者:
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( );
你想做什么?也许有更好的Perl方式来做你想要完成的任何事情.
例如,如果您不希望人们因为您想要强制执行封装而在您的对象中乱逛,您可以使用类似Class :: InsideOut的东西.该模块有一个Class :: InsideOut :: About文档模块,解释了这个概念.还有一些Object :: InsideOut,Brian Phillips已经提到过.