Com PHP, você consegue criar um código que gera outro código, afinal, um script PHP é um arquivo texto.
Mas a linguagem também permite que um script consiga alterar seu próprio comportamento em tempo de execução. Isso pode ser útil para otimizar trechos de código. Este recurso é possível com o comando "eval".
Abaixo é mostrado um exemplo de código que não usa e outro que usa a metaprogramação.
Na função abaixo, são feitas duas comparações a cada iteração do loop:
/** * Funcao de exemplo * @param array[int] $array Array de numeros * @param bool $somar Indica se o elemento do array deve ser somado com 1 * @param bool $multiplicar Indica se o elemento do array deve ser multiplicado por 2 * @return void */ function exemplo($array, $somar, $multiplicar) { foreach ($array as $elemento) { if ($somar) { $elemento += 1; } if ($multiplicar) { $elemento *= 2; } echo $elemento; } }
Usando metaprogramação, primeiro seria montando o código que desejamos executar, depois passariamos para que ele seja avaliado com "eval":
/** * Funcao de exemplo * @param array[int] $array Array de numeros * @param bool $somar Indica se o elemento do array deve ser somado com 1 * @param bool $multiplicar Indica se o elemento do array deve ser multiplicado por 2 * @return void */ function exemplo($array, $somar, $multiplicar) { $codigo = 'foreach ($array as $elemento) {'; if ($somar) { $codigo .= '$elemento += 1;'; } if ($multiplicar) { $codigo .= '$elemento *= 2;'; } $codigo .= 'echo $elemento;'; $codigo .= '}'; // Executar o codigo gerado dinamicamente eval($codigo); }
O segundo código tende a ser mais rápido pois na variável $codigo serão colocadas apenas as instruções desejaveis de serem realizadas durante o loop. Se forem passados os valores true e true para $somar e $multiplicar, então o código gerado na variável $codigo seria:
foreach ($array as $elemento) { $elemento += 1; $elemento *= 2; echo $elemento; }
Note que o loop não apresenta condições internamente, o que tornaria a iteração mais rápida.
Entretanto, trabalhar com metaprogramação não é recomendado para otimizar tudo. Pode ser utilizado em códigos de caixa preta, onde a implementação não costuma ser consultada, ou em trechos onde a performance precisa ser muito alta. Escrever um código e jogá-lo em uma variável é uma tarefa arriscada, já que o interpretador só conseguirá detectar erros de sintaxe no código gerado no momento em que o mesmo é avaliado (com o comando "eval"). Observe que isso incluem os delimitadores de instruções (ponto e vírgula), e tudo mais.
A metaprogramação torna o código menos legível e, por isso, também deve ser muito bem pensada antes de ser usada. Porém, abre brecha para construção de estruturas bastante interessantes. Observe o código abaixo:
$busca = 'if ($i == $elemento) { $achou = true; $busca = ""; }'; $elemento = 7; for ($i = 0; $i < 10; $i++) { eval($busca); echo $i; }
Este código imprime números de 0 a 9, só que o código também quer aproveitar as iterações do loop para checar se um determinado elemento foi impresso ou não. Assim que o elemento é encontrado, não é mais necessário checar nas próximas iterações. Logo, o código que guarda a busca passa a guardar nada. Quando uma string vazia é passada para "eval", nada é feito.
No exemplo, uma variável guardou um código capaz de mudar o seu próprio valor quando avaliado. Ela poderia mudar o código para outra coisa diferente de uma string vazia. Percebe o quanto a metaprogramação é complexa?
1 comentário
Gostei deste artigo!!!
Bem explicado e bastante interessante. Nunca tinha visto nada sobre metaprogramação!!!
Abraço
Postar um comentário
Nota: fique a vontade para expressar o que achou deste artigo ou do blog.
Dica: para acompanhar as respostas, acesse com uma conta do Google e marque a opção "Notifique-me".
Atenção: o blogger não permite inclusão de tags nos comentários, por isso, use algum site externo para postar seu código com dúvidas e deixe o link aqui. Exemplo: pastebin.com