Perl:在方法中调用时,ref($ self)可以返回除__PACKAGE__或undef之外的任何内容吗?

NXT*_*NXT 3 oop perl

我在类中有方法,我需要确保只在对象实例上调用,而不是作为类方法.

我可能会做这样的事情:

# Edit: this is terrible, don't do this, it breaks inheritance.
sub foo
{
  my ($self) = @_;

  if (ref($self) ne __PACKAGE__) { return; }

  ...do stuff
}
Run Code Online (Sandbox Code Playgroud)

但我认为这样做会更有效:

sub foo
{
  my ($self) = @_;

  if (not ref($self)) { return; }

  ...do stuff
}
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 是否可以安全地假设如果ref()返回不是undef,它将返回当前包?

  2. 理想情况下,我希望在我的所有方法中重新检查并执行类似的操作.这是个坏主意吗?

  3. 有没有更美好的方式来做我想要的?

在这种情况下,"使用驼鹿"不是一个可接受的答案.但是,如果您不得不这样说,请告诉我moose如何使这简单或更有效.我可能想将它合并到我自己的对象系统中.

谢谢!

编辑以反映ref永远不会返回undef,只是一个空字符串.

编辑2这是一个后续问题.以下有人建议使用:

$self->isa(__PACKAGE__)
Run Code Online (Sandbox Code Playgroud)

但这不会总能成功吗?当然除非呼叫者做了一些真正愚蠢的事情:

MyClass::MyMethod($ref_to_some_other_object)
Run Code Online (Sandbox Code Playgroud)

Sin*_*nür 7

首先,你可能不应该croak默默地做任何事情,因为根据你的规范,调用foo类方法是违反合同的.

其次,只检查第一个参数是否是参考就足够了.如果涉及继承,您的方法将失败:

#!/usr/bin/perl

package A;
use Carp;

sub new { bless {} => shift }
sub foo {
    croak "I am not in " . __PACKAGE__ unless __PACKAGE__ eq ref(shift)
}

package B;

use base 'A';

package main;

$x = B->new;

$x->foo;
Run Code Online (Sandbox Code Playgroud)
C:\Temp> t
I am not in A at C:\Temp\t.pl line 19

另见perldoc -f ref:

如果引用的对象已被保存到包中,则返回该包名称.您可以将其ref视为typeof 运营商.

所以:

sub foo {
    croak "Don't call as class method" unless ref shift;
}
Run Code Online (Sandbox Code Playgroud)

最后,请注意ref 永远不会返回undef.

将此检查添加到每个方法都是一个好主意吗?我猜一个人可以通过契约观点从设计中得出这个论点.

另一方面,我的方法假设它们被称为实例方法,并且我只检查方法被调用为类方法的可能性,如果该方法在被调用时可以提供有意义的替代行为.

我不记得任何有这些检查的模块.

顺便说一句,而不是

sub foo {
    my ($self) = @_;
Run Code Online (Sandbox Code Playgroud)

你应该使用

sub foo {
    my $self = shift;
Run Code Online (Sandbox Code Playgroud)

只留下方法中的参数@_进行解包.或者,您应该一举解压所有参数:

sub foo {
    my ($self, $bar, $baz) = @_;
Run Code Online (Sandbox Code Playgroud)