[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