A END blocks after being defined can't be changed! As mentioned in perlmod, they will be called on global destruction in reverse order (Last to In First to Out - LIFO).
The only way to change this END block is to do some perlhack, building a XS module. I have worked on that to can call END block at runtime, and to undef the END blocks of a package that I already have called:
XS
void
get_end_subs( pkg )
char * pkg
PREINIT:
CV *cv_end ;
PPCODE:
if ( PL_endav ) {
long i ;
SV **svp = av_fetch(PL_endav , 0 , FALSE) ;
long lng = av_len( PL_endav ) ;
EXTEND(SP, lng + 1 ) ;
for( i = 0 ; i <= lng ; ++i ) {
cv_end = (CV *) svp[i] ;
if ( !strcmp( HvNAME(CvSTASH(cv_end)) , pkg) ) {
PUSHs( newRV_inc( cv_end ) );
}
}
}
void
undef_end_subs( pkg )
char * pkg
PREINIT:
CV *cv_end ;
CV *cv_null ;
PPCODE:
if ( PL_endav ) {
long i ;
SV **svp = av_fetch(PL_endav , 0 , FALSE) ;
long lng = av_len( PL_endav ) ;
cv_null = get_cv("Safe::World::NULL_END_SUB" , TRUE) ;
for( i = 0 ; i <= lng ; ++i ) {
cv_end = (CV *) svp[i] ;
if ( !strcmp( HvNAME(CvSTASH(cv_end)) , pkg) ) {
cv_undef( cv_end ) ;
svp[i] = cv_null ;
SvREFCNT_inc( cv_null ) ;
}
}
}
The undef_end_subs() function will set the END blocks that I don't want to have them executed to a null SUB defined at &Safe::World::NULL_END_SUB.
And here's a example of use:
my $packname = 'foo::bar' ;
foreach my $end_i ( get_end_subs($packname) ) {
eval{ &$end_i() if $end_i ; } ;
}
undef_end_subs($packname) ;
I think that you can get this sources and change to do what you want, let's say, change the order of the END blocks at PL_endav, etc...
Note that PL_endav is a AV, so, you can build a XS function that return it as a normal Perl ARRAY, and do all your changes with Perl code, but you also will need a function that get informations about the values in this array to know if it's the right END block (CODE).
Also you can use the B module to do that. If you've got a recent enough version of perl (5.7+ IIRC) you already have the module. Example of use:
use B;
sub B::exec_ENDs {
my $pkg = caller;
$_->object_2svref->()
for grep { $_->GV->STASH->NAME eq $pkg } B::end_av->ARRAY;
}
{
package foo;
sub pretend_to_leave {
B->exec_ENDs();
print "I'll go get my coat ...\n";
}
END { print "... another END block\n" }
END { print "foo: this will be followed by " }
}
foo->pretend_to_leave();
END { print "main: Right, I'm outta here\n" }
__output__
foo: this will be followed by ... another END block
I'll go get my coat ...
main: Right, I'm outta here
foo: this will be followed by ... another END block
Enjoy! ;-P
Graciliano M. P.
"Creativity is the expression of the liberty".
|