PHP / refactoring: Como ?

15 04 2007

Refatorar código em PHP normalmente não é simples.

As IDEs que mais utilizei até hoje, como pdt (aka eclipse + plugins), zend studio e quanta plus não oferecem (ou não ofereciam na época) suporte a nenhum tipo de refatoração. Nada de renomear variável, função, classe, método.

Talvez a maior dificuldade em se trabalhar com com isso seja a tipagem fraca do PHP (somente talvez). Mas alguns trabalhos encontrados na internet, como por exemplo o phc – php compiler (não se deixe enganar pelo nome), podem ajudar: Há aqui um exemplo de como modificar chamadas de uma função para outra. Bastante trabalho para uma tarefa relativamente simples; O phc transforma o código php em uma AST – Abstract Syntax Tree e o exemplo atravessa essa árvore efetuando as modificações.

Algumas classes implementadas em PHP mesmo também são encontradas no PEAR. Mas também não há nada que seja muito utilizável.

Acredito que o que se tenha de mais “útil” no momento são as funções da extensão tokenizer (que é compilada por padrão). Com ela podemos trabalhar mais facilmente com um script, para criarmos algum tipo de ferramenta útil para refatoração. Vejamos por exemplo, como criar uma função para modificar o nome de uma variável:


<?php
// arquivo sample.php

$foo   ‘foo’;
$hello “Ola $foo\n”;

// variavel $foo no comentario nao sera modificada

function foo()
{
    
// variavel $foo neste contexto sera modificada
    
$foo ‘1’;
    echo 
$foo;
}
    
echo 
$hello;
?>


<?php
// arquivo change_var_name.php

/**
 * Funcao que ira modificar o nome de uma variavel
 *
 * @param  array  $tokens  Array com os tokens a serem analisados
 * @param  string $oldName Nome da variavel que sera modificada
 * @param  string $newName Novo nome da variavel
 * @return string Codigo-fonte referente aos tokens fornecidos, com a 
 * variavel devidamente modificada
 */
function changeVarName($tokens$oldName$newName)
{
    
// variavel que ira conter o codigo-fonte a ser retornado
    
$ret ;
    
    
// como $tokens e’ um array, utilizamos foreach para
    // passar por todos os seus itens
    
foreach ($tokens as $token) {
    
        
// quando se obtem os tokens de um arquivo, eles vem em um 
        // array contendo o numero do token e o valor ou em uma string,
        // contendo apenas o valor. Entao verificamos qual o caso.
        
if (!is_array($token)) {
            
$tokenName  false;
            
$tokenValue $token;
        } else {
            
$tokenName  token_name($token[0]);
            
$tokenValue $token[1];
        }

        // se nao ha o nome/numero do token, siginifica que ele nao e’ uma variavel,
        // pois elas contem o numero e o valor. Entao podemos adicionar o token ao
        // codigo-fonte que sera retornado e passar para o proximo token
        
if (!$tokenName) {
            
$ret .= $tokenValue;
            continue;
        }        
        
        
// verificamos se o token e’ uma variavel – T_VARIABLE. Se nao for, adicionamos
        // o valor do token ao codigo-fonte que sera retornado e passar para o proximo token
        
if ($tokenName != ‘T_VARIABLE’) {
            
$ret .= $tokenValue;
            continue;
        }

        // verificamos se o valor do token, ou seja, o nome da variavel, e’ o mesmo
        // que queremos modificar. Se nao for, o processo e’ o mesmo do anterior, adicionamos
        // o valor ao codigo-fonte e passamos para o proximo token
        
if ($tokenValue != $oldName) {
            
$ret .= $tokenValue;
            continue;
        }

        // se chegou ate aqui, significa que o token e’ uma variavel e tem o nome que
        // precisa ser modificado. Entao modificamos o valor do token e o adicionamos ao
        // codigo-fonte que sera retornado
        
        
$tokenValue $newName;
        
$ret .= $tokenValue;
    }
    
    
// retornamos o fonte
    
return $ret;
}

// exemplo de uso da funcao

// obtemos o conteudo do arquivo que iremos modificar
$arquivo file_get_contents(‘sample.php’);

// e utilizamos a funcao token_get_all para obter todos
// os tokens do arquivo. Observe que tudo no script e’
// tratado como sendo um token
$tokens  token_get_all($arquivo);

// modificamos $foo para $bar
$bla changeVarName($tokens‘$foo’‘$bar’);

echo $bla;

E, executando:

$ php change_var_name.php
<?php
// arquivo sample.php

$bar = ‘foo’;
$hello = "Ola $bar\n";

// variavel $foo no comentario nao sera modificada

function foo()
{
// variavel $foo neste contexto sera modificada
$bar = ‘1’;
echo $bar;
}

echo $hello;
?>

Exemplo bem simples de como poderiamos utilizar tokenizer para refatorar código. Observe que o nome da variável foi modificada tanto no contexto global, quanto no contexto da função “foo”. Alguns outros detalhes poderiam ser observados, mas quem sabe em um post futuro.

É bem possível (e acho que relativamente fácil) trabalhar melhor neste exemplo para se definir onde se deseja modificar a variável. E quem sabe nos próximos dias escrever uma classe para refatorar realmente, permitindo modificar nome funções, classes e outras coisas úteis.

E para quem não sabe o que é refatoração, vale uma lida no artigo da wikipedia e em Refactoring Home Page.

Anúncios

Ações

Information

4 responses

24 04 2007
Rael

Cara, incrível… eu também estava procurando alguma IDE com refactor, e nem o PDT ou ZDE, da própria Zend tem isso disponível.
Só ter um rename e um “encapsulate fields” já ajudaria muito!

27 04 2007
E Silva

Pois é, se eventualmente tiver tempo, é possível que faça um plugin para o PDT, pra disponibilizar isso.

Se eu tivesse tempo… : )

25 05 2007
PHP / refactoring: Como ? (Parte 2) « PHP-BR

[…] PHP / refactoring: Como ? (Parte 2) Pois é, eu não sabia que teria parte 2, mas este é para ser uma continuação do post PHP / refactoring: Como ?. […]

22 09 2007
PHP / refactoring: Como ? (Outra vez) « PHP-BR

[…] / refactoring: Como ? (Outra vez) Já havia  comentado aqui alguma coisa. Mas aqui encontramos um artigo muito legal sobre […]

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s




%d blogueiros gostam disto: