[SP-pm] E eu não usei AUTOLOAD... [Was: Boas vindas ao Igor Sutton Lopes]
Igor Sutton
igor.sutton em gmail.com
Terça Fevereiro 13 09:26:59 PST 2007
> Ainda sobre o AUTOLOAD:
>
> 1. Quem usa? Prá que usa?
Eu nunca usei. Na verdade acredito que você utiliza o AUTOLOAD prá
coisas mágicas que 99% das pessoas não necessitam utilizar.
O módulo CGI utiliza AUTOLOAD, eu copiei a implementação e vamos
tentar ver passo a passo o que ele faz.
sub AUTOLOAD {
print STDERR "CGI::AUTOLOAD for $AUTOLOAD\n" if $CGI::AUTOLOAD_DEBUG;
my $func = &_compile;
goto &$func;
}
Segundo a documentação do goto (perldoc -f goto), "goto &$func" sai
imediatamente da rotina, elimina quaisquer variáveis locais (definidas
por local) e chama a rotina $func passando como parâmetro @_. Coloquei
a definição da função _compile mais abaixo, para analisarmos.
sub _compile {
# aqui, $AUTOLOAD tem o FQDN da função chamada. por exemplo,
# CGI::my_silly_test()
my($func) = $AUTOLOAD;
my($pack,$func_name);
{
local($1,$2); # this fixes an obscure variable suicide problem.
# separamos pacote e nome de função
$func=~/(.+)::([^:]+)$/;
($pack,$func_name) = ($1,$2);
$pack=~s/::SUPER$//; # fix another obscure problem
$pack = ${"$pack\:\:AutoloadClass"} || $CGI::DefaultClass
unless defined(${"$pack\:\:AUTOLOADED_ROUTINES"});
# armazena em $sub a referência para o hash PACOTE::SUBS
my($sub) = \%{"$pack\:\:SUBS"};
# verifica se %$sub não está vazio. $sub é uma referência para
um hash, onde
# a chave é o nome da função requerida e o código é o valor.
unless (%$sub) {
# obtém a referência de PACOTE::AUTOLOADED_ROUTINES
my($auto) = \${"$pack\:\:AUTOLOADED_ROUTINES"};
local ($@,$!);
# cria em runtime a função no pacote
eval "package $pack; $$auto";
croak("$AUTOLOAD: $@") if $@;
$$auto = ''; # Free the unneeded storage (but don't undef it!!!)
}
# obtem a referencia do código da função.
my($code) = $sub->{$func_name};
# cria uma função vazia no pacote caso $code não exista e o
nome da função seja
# DESTROY
$code = "sub $AUTOLOAD { }" if (!$code and $func_name eq 'DESTROY');
# verifica se $code não existe.
if (!$code) {
# algumas verificações referentes à configuração de exportação.
(my $base = $func_name) =~ s/^(start_|end_)//i;
if ($EXPORT{':any'} ||
$EXPORT{'-any'} ||
$EXPORT{$base} ||
(%EXPORT_OK || grep(++$EXPORT_OK{$_},&expand_tags(':html')))
&& $EXPORT_OK{$base}) {
$code = $CGI::DefaultClass->_make_tag_func($func_name);
}
}
croak("Undefined subroutine $AUTOLOAD\n") unless $code;
local ($@,$!);
# já vimos este código antes. nasty!
eval "package $pack; $code";
if ($@) {
$@ =~ s/ at .*\n//;
croak("$AUTOLOAD: $@");
}
}
CORE::delete($sub->{$func_name}); #free storage
return "$pack\:\:$func_name";
}
> 2. Quem usa, alguma vez sobrecarregou o UNIVERSAL::can() para
> condizer com o que você faz no AUTOLOAD? Como?
Eu li algo a respeito disso no best practices do Damian. Segundo ele é
um pé-no-saco fazer isto funcionar direito e pode levar a bugs quase
imperceptiveis.
A regra geral é: não use :-)
--
Igor Sutton Lopes <igor.sutton em gmail.com>
Mais detalhes sobre a lista de discussão SaoPaulo-pm