Como usar metaprogramação em PHP?
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:
Usando metaprogramação, primeiro seria montando o código que desejamos executar, depois passariamos para que ele seja avaliado com "eval":
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:
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:
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?
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] $vetor Vetor de numeros
* @param bool $somar Indica se o elemento do vetor deve ser somado com 1
* @param bool $multiplicar Indica se o elemento do vetor deve ser multiplicado por 2
* @return void
*/
function exemplo($vetor, $somar, $multiplicar) {
foreach ($vetor 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] $vetor Vetor de numeros
* @param bool $somar Indica se o elemento do vetor deve ser somado com 1
* @param bool $multiplicar Indica se o elemento do vetor deve ser multiplicado por 2
* @return void
*/
function exemplo($vetor, $somar, $multiplicar) {
$codigo = 'foreach ($vetor 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 ($vetor 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?
comentários (0)
suspender
Lista de Respostas:
09/03/2011 11:13am
(~14 anos atrás)
(~14 anos atrás)
eu não sei pq o pessoa fica negativando um material tão importante como esse que o rubens nos passou...
é importante conhecermos um pouco sobre metaprogramação em PHP...
Valeu pelo FAQ Rubens... Parabéns!
é importante conhecermos um pouco sobre metaprogramação em PHP...
Valeu pelo FAQ Rubens... Parabéns!