Category: Modules Keywords: attributes
用过 Catalyst 的人都知道 Catalyst 的 action 都要用 : Global, : Local, : Path(), : Regex 等等来 register.这种 sub subroutine : attributes 虽然在 perldoc attributes 里说还是试验性的,但是看起来不会再有大的改变。
不过代码写起来却不是很舒服。我不打算翻译 attributes, 而是写几个简单的例子来试验试验其在 sub 上的功能。一个最最简单的例子是:
use strict;test();sub MODIFY_CODE_ATTRIBUTES {
my ($pkg, $ref, @attrs) = @_; print "$pkg\n";
print "attrs: $_\n" foreach @attrs; return;
}sub test : attribute {
print "test";
}1;输出的结果:main
attrs: attribute
test
- 简单的解释一下:
- MODIFY_CODE_ATTRIBUTES 根据 perldoc attributes 的介绍,将对每一个拥有 attributes 属性后缀的子程序都执行一次。而且对于子程序的执行时间是在 complie 编译时执行。所以 main attrs: attribute 会出现在 test 前面。
- my ($pkg, $ref, @attrs) = @_; 这三个参数分别对应 包名(这里是 main),$ref 为拥有后缀的子程序的引用(这里的 $ref 差不多是 \&test),而 @attrs 就是那属性后缀名。为什么这里是用 @attrs 是因为属性后缀可以是多个。比如 sub test : attribute kisssherry { 的话我们的输出就会变为
main
@attrs 接收了 attribute 和 kisssherry
attrs: attribute
attrs: kisssherry
test - 另外得注意的是返回。return 1 是绝对不允许的,return 返回的必须是一个属性列表,作用是配合类继承。
package Catalyst::AttrContainer;use strict;唯一使用了这个类的 Catalyst 模块是 Catalyst::Base;
use base qw/Class::Data::Inheritable Class::Accessor::Fast/;use Catalyst::Exception;
use NEXT;__PACKAGE__->mk_classdata($_) for qw/_attr_cache _action_cache/;
__PACKAGE__->_attr_cache( {} );
__PACKAGE__->_action_cache( [] );# note - see attributes(3pm)
sub MODIFY_CODE_ATTRIBUTES {
my ( $class, $code, @attrs ) = @_;
$class->_attr_cache( { %{ $class->_attr_cache }, $code => [@attrs] } );
$class->_action_cache(
[ @{ $class->_action_cache }, [ $code, [@attrs] ] ] );
return ();
}sub FETCH_CODE_ATTRIBUTES { $_[0]->_attr_cache->{ $_[1] } || () }
package Catalyst::Base;use strict;这样诸位应当知道为什么我们每在一个 Controller 里都要写上 use base 'Catalyst::Base'; 了吧。它的目的就是解析类如 Global/Path/Local 等 attributes. 没写 use base 'Catalyst::Base'; 的话,action 里根本就不会出现你写的 Controller.
use base qw/Catalyst::Component Catalyst::AttrContainer Class::Accessor::Fast/;...
而即使现在的 Catalyst 将 Catalyst::Base 拆分为 Catalyst::Controller Catalyst::Model Catalyst::View 后, Catalyst::Controller 目前的代码也只是:
package Catalyst::Controller;use strict;另外有个 Attribute::Handlers 用于专门处理 attributes, 其实也差不多,看看 perldoc 就 OK 了。
use base qw/Catalyst::Base/;1;