• Otimizando código com __autoload

    by  • January 10, 2007 • PHP

    O advento do PHP5 trouxe consigo outra ótima ferramenta para otimizar seu código, se trata do __autoload. Esta função pode reduzir o tempo perdido na hora de se incluir arquivos de objetos e classes em seu código. Mas como otimizar e criar uma função __autoload?

    Esta função é responsável por uma tarefa simples: ao identificar a chamada a uma nova classe (ex: new ObjetoX), o PHP procura a declaração desta classe, caso o mesmo não seja encontrado é então chamado o método __autoload() que deve incluir o arquivo desta classe com sua declaração, ai então é feita a instância do objeto.

    Qual a vantagem?

    Em sites de grande porte geralmente, caso o desenvolvedor seja organizado claro, classes são declaradas em arquivos separados, e podem acabar sendo muitos, especialmente se trabalhando de forma OO. Com isso o que geralmente acontece é que um arquivo central é responsável por incluir todos os arquivos de declaração, sem saber ao certo se todos objetos serão usados neste script. Isto causa o overhead, carregando arquivos de forma inútil, causando um tempo de processamento maior do que o necessário.

    Utilizando o autoload é possível carregar arquivos externos apenas no caso de serem necessários, evitando este overhead e poupando o acesso a disco e processamento.

    Qual a desvantagem?

    Já dizia um velho sábio que toda moeda tem dois lados. Da mesma forma que se ganha tempo não carregando outros arquivos externos pode-se perder tempo no momento da instanciação do objeto, que podemos considerar muito pequeno para ser levado em conta, mas desvantagem é desvantagem.

    Como implementar __autoload() no meu site?

    Primeiramente devemos analisar a estrutura de arquivos de seu site, e desenhar a função autoload de acordo com isso, determinando um padrão de nomenclatura de objetos, para evitarmos problemas.

    Na estrutura deste exemplo temos três situações:
    - Classe da Biblioteca ezComponents: localizados no include_path do PHP
    - Classes gerais: localizadas no diretório /lib
    - Classes de negócio: Localizadas no diretório /lib/gcc/sistema (onde sistema varia, ex: inet ou ind)

    A função autoload deve saber em qual destas pastas deve buscar a classe específica que procura. Porém a classe autoload tem apenas um parâmetro: o nome da classe

    void __autoload(string $class_name)

    Desta forma a mágica de tudo esta na padronização dos nomes das Classes. Neste caso decido fazer três padrões:
    - Classes ezComponents sempre iniciam com “ezc”
    - Classes de negócio sao nomeadas gcc{cod_sistema}{Objeto}, por exemplo: gccInetAgenda
    - Outras classes podem ter qualquer tipo de nome.

    Desta forma o PHP já saberia em qual pasta procurar o arquivo, mas como identificar o arquivo? Mais uma padronização era necessária: o nome do arquivo deve ser sempre {nome_da_classe}.class.php, respeitando letras maiúsculas e minúsculas.

    Então com estes padrões a missão ficou simples, a função deve identificar o tipo de classe, e rodar o algoritmo específico de cada tipo, incluindo o arquivo com o nome certo. Apenas no caso das classes de negócio, onde decidi separar as classes por subsistema, mas uma expressão regular resolve rapidamente o problema.

    function __autoload( $className )
    {
    	if (strpos($className,'ezc') !== false){ //classe da ezComponents
    		ezcBase::autoload( $className );
    	}elseif (strpos($className,'gcc') !== false){ //classe de negócio
    		//Separar no nome, pasta, sistema e nome
    		ereg("(gcc)([A-Z]{1}[^A-Z]*)(.*)$",$className,$bits);
    		//Incluir arquivo combinando dados
    		include_once("lib/".$bits[1]."/".strtolower($bits[2])."/".$className.".class.php");
    	}else{
    		//incluir classe comum
    		include_once("lib/".$className.".class.php");
    	}
    }
    

    Pequeno porém, a função autoload é global, ou seja, não pode ser declarada duas vezes. Esta função deve ser declarada em um arquivo único e central. Mas em uma estrutura bem montada de sistema este problema dificilmente ocorrerá.

    Qual o impacto final?

    Se formos comparar a diferença de resultados em um arquivo, por carregamento, podemos não ficar muito impressionados, porém ao se pensar um um servidor com múltiplas conexões concorrentes, e milhares de carregamentos por dia, pense bem.

    No exemplo que usei para fazer os testes, criei duas estruturas paralelas onde incluía arquivos, e instanciava um objeto. Num exemplo usei o autoload e no outro carreguei todos as classes normalmente.

    Foram incluídas no total 8 classes em arquivos externos. Obviamente que com um numero destes de classes é raro que todas sejam usadas em um mesmo arquivo, mas imagine um sistema onde as regras de negócio sao baseadas em objetos, você teria muitos objetos e usaria poucos por cada vez, mas sem o autoload teria de sempre inserir todos, ou inserir objetos certos e cada arquivo que usa, um tanto quanto trabalhoso.

    O resultado final foi o seguinte:
    Página com includes manuais: 0,0366659164429 segundos
    Página com uso do _autoload: 0,0239880084991 segundos

    Conclusão

    Em uma estrutura de sistema com ponto centralizado, e onde se deseja ter menos dor de cabeça ou trabalho incluindo cada classe, a função __autoload faz uma diferença significativa, e deve ser aproveitada. Ainda não encontrei desvantagens significativas da função que possam afetar o resultado final negativamente. Caso conheça alguma coisa deixe um comentário, ele será bem-vindo.

    This post is also available in: Inglês

    About

    Rafael Dohms is a PHP Evangelist, Speaker and contributor. He is a very active member of the PHP Community, having helped create and manage two PHP User Groups in Brazil. He shared the lead of PHPSP for 3 wonderful years making a positive mark on the local market. Developer, gamer and lover of code he also hosts Brazil’s first PHP Podcast: PHPSPCast, as well as contributing to well known projects. He moved to the Netherlands in search of new challenges and is now part of the team at WEBclusive, sharing his passion for quality code and working on new awesome ideas with the team. You can always find him at the nearest Community events, speaking, sharing, talking or just learning from the rest.

    http://doh.ms