Otimizando código com __autoload

  • PHP
  • January 10, 2007

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.

Tags:
comments powered by Disqus

Related Posts

PHP Magazine: Edição 5

PHP Magazine: Edição 5

  • August 12, 2008

Voltando de um período quieto, a PHP Magazine lançou hoje a sua 5a edição.

Read More
Novas do Google

Novas do Google

  • July 8, 2006

Quem trabalha ou convive comigo já esta acustumado a ouvir “google is god” ou “google vai dominar o mundo”.

Read More
php|tek09: Day #2

php|tek09: Day #2

  • May 21, 2009

Ok, i might be a little “DUI” as I write this, but bear with me, i can get it done.

Read More