Perl 从方法修饰符在运行时应用角色
我有一个角色提供一个方法修饰符,如下所示:Perl 从方法修饰符在运行时应用角色,perl,moose,Perl,Moose,我有一个角色提供一个方法修饰符,如下所示: package MyApp::Role::MenuExtensionRed; use Moose::Role; requires 'BuildMenu'; after 'BuildMenu' => sub {...}; 由于其他地方的要求,我需要在运行时应用许多角色,如下所示: package MyApp::MainMenu before 'BuildMenu' => sub { my ( $self, $args ) =
package MyApp::Role::MenuExtensionRed;
use Moose::Role;
requires 'BuildMenu';
after 'BuildMenu' => sub {...};
由于其他地方的要求,我需要在运行时应用许多角色,如下所示:
package MyApp::MainMenu
before 'BuildMenu' => sub {
my ( $self, $args ) = @_;
my $roles = $args->{menu_extensions};
apply_all_roles($self,@$roles);
};
sub BuildMenu {...}
但是,永远不会调用“after”方法修饰符。很明显,我违反了一些规则,但我真的很想理解为什么这不起作用
如果我在BUILD方法中应用角色,而不是在“BuildMenu”之前应用角色,那么它是有效的。但不幸的是,我的菜单扩展角色列表此时不可用,所以我不得不等待
如有其他解决方案,将不胜感激
编辑有趣的是,在调用“BuildMenu”之后调用了
,
,但仅在随后调用BuildMenu时调用。因此,一个方法的修饰符不能从它自己的另一个修饰符中进行更改。这是预期的行为吗?有没有办法在运行时添加到修饰符的“列表”中?这是其实现方式的副作用
使用方法修改器时,它们基本上会用新方法替换现有方法,并且新方法包含对旧方法的引用
所以当你看到
before foo => sub {
}
角色组合时发生的情况是:
my $orig = *package::foo;
*package::foo = sub {
$beforetrigger->( @args );
return $orig->( @args );
}
或多或少
想象一下,您有两个sub,“A”是在应用角色之前调用的BuildMenu版本,“B”是在应用角色之后调用的BuildMenu版本
那么发生了什么,你的电话订单是这样的:
First Call ->
A ->
before ->
apply roles ->
replace A with B
<-- return from before
A body ->
<-- return from A Body
Subsequent Call
B -> something
注意,这段代码可能有一个有趣的地方,$wrapped_sub是我刚刚编写的应用角色的sub。。。我还没有弄清楚那里会发生什么,但是你可能需要设置一些条件来防止一个自我调用的子死亡循环发生
但问题的要点基本上可以归结为这样一个事实:您不能将正在执行的sub替换为sub本身的新sub,并期望它自动菊花链,因为被替换的sub本身并不知道它正在被替换,而且因为“方法修饰符”相当于用链接到旧潜艇的新潜艇替换潜艇=)只是一个猜测,但它可能会在进入潜艇时检查前/后包装器。谢谢你的回答!有道理!
around foo => sub {
my ( $orig, $self , @args ) = @_;
# apply role to $self here
# this gets the sub that will be resolved *after* the role is applied
my $wrapped_sub = $self->can('foo');
my $rval = $wrapped_sub->( $self, @args );
return $wrapped_sub->( $self, @args );
}