一个已知的内置Perl功能是属性。然而,官方
documentation做一个相当不好的工作介绍新手的概念。同时,像Catalyst的框架广泛使用属性,似乎使许多事情更容易。因为使用的东西,不知道的含义吸了一点,我想知道的细节。语法上看,他们看起来像Python的装饰器,但文档意味着更简单。
你能解释(用真实的例子,如果可能的话)什么属性是有益的和在门后发生什么?
解决方法
你是对的,文档在这方面不是很清楚,特别是因为属性不那么复杂。如果你定义一个子程序属性,像这样:
sub some_method :Foo { }
Perl会在编译你的程序时(这很重要)在当前包或其任何父类中寻找魔法子MODIFY_CODE_ATTRIBUTES。这将使用当前包的名称,对您的子例程的引用以及为此子例程定义的属性的列表来调用。如果此处理程序不存在,编译将失败。
你在这个处理程序中做什么完全取决于你。恩,那就对了。没有隐藏的魔法。如果要发出错误信号,返回违规属性的名称将导致编译失败,并显示“无效属性”消息。
还有一个称为FETCH_CODE_ATTRIBUTES的处理程序,只要有人说,就会被调用
use attributes; my @attrs = attributes::get(\&some_method);
这个处理程序得到传递的包名和子程序引用,并且应该返回一个子程序的属性的列表(虽然你真正做的是再次取决于你)。
下面是一个示例,用于简单地“标记”具有任意属性的方法,您可以稍后查询:
package MyClass; use Scalar::Util qw( refaddr ); my %attrs; # package variable to store attribute lists by coderef address sub MODIFY_CODE_ATTRIBUTES { my ($package,$subref,@attrs) = @_; $attrs{ refaddr $subref } = \@attrs; return; } sub FETCH_CODE_ATTRIBUTES { my ($package,$subref) = @_; my $attrs = $attrs{ refaddr $subref }; return @$attrs; } 1;
现在,在MyClass及其所有子类中,可以使用任意属性,并使用属性:: get()查询它们:
package SomeClass; use base 'MyClass'; use attributes; # set attributes sub hello :Foo :Bar { } # query attributes print "hello() in SomeClass has attributes: ",join ',',attributes::get(SomeClass->can('hello')); 1; __END__ hello() in SomeClass has attributes: Foo,Bar
总之,属性不会做太多,另一方面使它们非常灵活:你可以使用它们作为真正的“属性”(如这个例子所示),实现类似装饰器(见Sinan’s answer),或为自己狡猾的目的。