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

The road to PHP 5.3: Namespaces

The road to PHP 5.3: Namespaces

  • August 12, 2008

We have all been looking forward to PHP6 and the big changes that were proposed for it, but along the way the PHP Core dudes made a great decision and split the PHP6 release in two.

Read More
Usando o PHP-SDK para rodar FQL na API do Facebook

Usando o PHP-SDK para rodar FQL na API do Facebook

  • February 15, 2011

Desde a migração do Facebook para a nova Graph API e o protocolo OAuth 2.

Read More
Pequenas mudanças

Pequenas mudanças

  • August 23, 2008

Caro leitor frequente, Você que acompanha este blog desde seu início, em 2006 percebeu que ele sempre rondou em torno de assuntos web, mas sempre com um foco em PHP.

Read More