perl子程序参考

awa*_*416 0 validation perl constructor reference subroutine

我有一组字段,每个字段都有不同的验证规则集.

我已经放置了子例程引用来验证hash-ref.

目前它在我的构造函数中,但我想从私有子中的构造函数中取出它.

我做了如下

sub new {
my $class = shift;
my $self  = {@_};

$class = (ref($class)) ? ref $class : $class;
bless($self, $class);

$self->{Validations} = {
  Field1 => {name => sub{$self->checkField1(@_);},args => [qw(a b c)]}
  Field2 => {name => sub{$self->checkField2(@_);},args => {key1, val1}}
..
..
..
..
};

return $self;
}
Run Code Online (Sandbox Code Playgroud)

现在我想从我的构造函数中取出所有这些验证规则,并希望做下面的事情,这样我就可以更好地控制基于类型字段的验证规则.(假设某些规则在一组字段中很常见并且我可以通过覆盖字段的值来覆盖其他规则的规则.)

bless($self, $class);

  $self->{Validations} = $self->_getValidation($self->{type});

  return $self;
}
sub _getValidation{
     my ($self,$type) = @_;
     my $validation = {
     Field1  => {name => sub {$self->checkField1(@_);}, args => {key1 => val1}},};

     return $validation;
}
Run Code Online (Sandbox Code Playgroud)

但我得到了Can't use string ("") as a subroutine ref while "strict refs" in use at...任何人都可以告诉我为什么这个行为与sub ref.如果我检查我的名字密钥,它将变为null或sub {DUMMY};

dao*_*oad 5

在我看来,你正在接近重塑麋鹿.考虑使用Moose而不是构建类似的东西,但不太有用.

错误消息表示您在代码需要代码引用的位置传入字符串.获取堆栈跟踪以确定错误的来源.

您可以使用Carp :: Always,覆盖$SIG{__DIE__}处理程序以生成堆栈跟踪或Carp::confess在代码中插入代码来执行此操作.

这是一个sigdie解决方案,将其粘贴在您的代码中,它将在模块初始化之前运行:

$SIG{__DIE__} = sub { Carp::confess(@_) };
Run Code Online (Sandbox Code Playgroud)

您可能需要将其放在一个BEGIN块中.

我真的很想阻止你采用这种方法来构建物体.你很高兴祝福作为你对象的一部分传入构造函数的随机垃圾!你轻快地伸手进入你的物体内部.字段验证规则*属于构造函数 - 它们属于属性mutators.

如果您必须使用DIY对象,请清理您的做法:

# Here's a bunch of validators.
# I set them up so that each attribute supports:
#   Multiple validators per attribute
#   Distinct error message per attribute
my %VALIDATORS = (

    some_attribute  => [
        [ sub { 'foo1' }, 'Foo 1 is bad thing' ],
        [ sub { 'foo2' }, 'Foo 2 is bad thing' ],
        [ sub { 'foo3' }, 'Foo 3 is bad thing' ],
    ],
    other_attribute => [ [ sub { 'bar' }, 'Bar is bad thing' ] ],

);


sub new {
    my $class = shift;  # Get the invocant
    my %args = @_;      # Get named arguments

    # Do NOT make this a clone method as well   

    my $self = {};
    bless $class, $self;

    # Initialize the object;
    for my $arg ( keys %args ) {

        # Make sure we have a sane error message on a bad argument.
        croak "Bogus argument $arg not allowed in $class\n"
            unless $class->can( $arg );

        $self->$arg( $args{$arg} );
    }

    return $self;
}

# Here's an example getter/setter method combined in one.
# You may prefer to separate get and set behavior.

sub some_attribute {
    my $self = shift;

    if( @_ ){
        my $val = shift;

        # Do any validation for the field
        $_->[0]->($val) or croak $_->[1]
            for @{ $VALIDATORS{some_attribute} || [] };

        $self->{some_attribute} = $val;
    }

    return $self->{some_attribute};

}
Run Code Online (Sandbox Code Playgroud)

所有这些代码都非常好,但您必须为每个属性重复属性代码.这意味着很多容易出错的样板代码.您可以通过学习使用闭包或字符串eval来动态创建方法来解决这个问题,或者您可以使用Perl的许多类生成库之一,如Class :: Accessor,Class :: Struct,Accessor :: Tiny等等. .

或者你可以学习[驼鹿] [3].Moose是新的(ish)对象库,它已经接管了Perl OOP实践.它提供了一组强大的功能,与经典的Perl OOP相比,大大减少了样板:

use Moose;

type 'Foo'
    => as 'Int'
    => where {
        $_ > 23 and $_ < 42
    }
    => message 'Monkeys flew out my butt';

has 'some_attribute' => (
    is  => 'rw',
    isa => 'Foo',
);
Run Code Online (Sandbox Code Playgroud)