How do I define private or internal methods in object oriented Perl?

这一生的挚爱 提交于 2019-12-04 03:14:57
Evan Carroll

Don't use the PBP for object practices. It is very old. In fact, now the best practices regarding Perl and objects can be found in Moose, an almost must-have for Perl.

In short, the way Perl blurs namespaces and classes most methods can be called statically on the class. This is not a bad thing, just don't document it. There is really no reason to want to seal the methods into the instance. Not having private methods is kind of annoying but the convention of not relying on undocumented methods is so strong it has sufficed for our community.

A trait is effectively a role (doesn't permit instantiation) that can be compiled into an object at runtime. This will further obscure the origin of the methods from your typical user (because they won't be in the original class), but it comes at a runtime cost. See MooseX::Traits for more information on traits.

The prepending underscore is a great convention to further state the method is private to peering eyes.

As a last note if you really want to push this issue, you might be able to create an anonymous class with those methods using Class::MOP::Class->create_anon_class()

package Foo;

## declare inside-out hashes here:

my %attr_a;
my %attr_b;

## declare private methods here

my $private_1 = sub {
  my $self = shift;
  # can use $attr_a{$self} here...
  ...
};

my $private_2 = sub {
  my $self = shift;
  ... 
};

## public methods here

sub new { ... }

sub public_1 {
  my $self = shift;
  # can access attributes here
  # can call private methods too, with slightly odd syntax:
  my $result = $self->$private_1(@args);
  ...
}

1;

Sort of. You can't hide a subroutine that's installed into the symbol table, but you can use a lexical variable to hold a reference to an anonymous subroutine:

package SOD::MyOOInterface;

my $some_method = sub { ... }

$some_method->();

Because $some_method is only visible in the file implementing the class, the subroutine can't be called externally. The drawback is that it can't be called as a method, it must be called as a function. If you want to use it as a method you'll have to pass the object reference explicitly:

$some_method->($obj, @args);

The way I deal with this is to add something like this at the start of the method:

my $self = shift;
croak "Instance method called on class" unless ref $self;

It's in no way true encapsulation, but it does mean someone calling you via the package will have to pass an object instance as the first argument. In general with Perl, I find there isn't much point in protecting against malicious users of my API - this just helps me catch situations where I accidentally try calling the method as a class method (which happens more often than I'd like to admit).

Personally, I think the underscore convention + clearly documenting the method as private (or not documenting it at all so it doesn't show up in the POD) is sufficient for real-world use. This is also how it works in Python. It's part of the language philosophy of not restricting users.

A Perl module would prefer that you stay out of its living room because you weren't invited, not because it has a shotgun...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!