Refatoração de código legado em PHP: do A ao Z
\n\nTrabalhar com código PHP legado é uma realidade inevitável para muitos desenvolvedores. Projetos escritos há 5-10 anos geralmente são "código espaguete" com variáveis globais, mistura de lógica de negócios e apresentação, falta de tipagem e funções obsoletas (mysql_*, ereg, etc.). Neste artigo, vamos abordar uma abordagem passo a passo para refatorar código PHP legado, permitindo melhorar o projeto sem interromper seu funcionamento.
\n\nPor que refatorar código legado é difícil?
\n\nO principal problema do código legado é a falta de testes. Você não pode ter certeza de que as alterações não quebrarão a funcionalidade existente. Dificuldades adicionais:
\n\n- \n
- Falta de documentação — a lógica de funcionamento geralmente é incompreensível \n
- Mistura de camadas — consultas SQL dentro de templates HTML \n
- Estado global — variáveis acessíveis de qualquer ponto do código \n
- Padrões obsoletos — uso de register_globals, funções mysql_* \n
- Dependências rígidas — criação direta de objetos com
newdentro das classes \n
Preparação para a refatoração: criando uma "rede de segurança"
\n\nAntes de alterar o código, é necessário garantir que você conseguirá detectar erros. Aqui estão as etapas obrigatórias:
\n\n1. Adicionar testes de caracterização
\n\nTestes de caracterização (characterization tests) fixam o comportamento atual do código. Eles são escritos após o código ser escrito e permitem garantir que a refatoração não alterou o comportamento.
\n\n<?php\n// Exemplo de teste de caracterização para uma função legada\nclass LegacyCalculatorTest extends PHPUnit\\Framework\\TestCase\n{\n public function testCalculateTotal()\n {\n // Fixando o comportamento atual\n $result = legacy_calculate_total(100, 0.2);\n $this->assertEquals(120, $result);\n }\n}\n\n\n2. Criar uma "cobertura" de testes
\n\nComece com testes de integração que verificam os principais cenários de usuário (cadastro, finalização de pedido, etc.). Isso dará uma confiança básica durante a refatoração.
\n\nEstratégia passo a passo para refatorar código PHP legado
\n\nUtilizamos a abordagem "Strangler Fig Pattern" (figueira estranguladora) — substituímos gradualmente os componentes antigos pelos novos, sem interromper o funcionamento do sistema.
\n\nPasso 1: Isole e encapsule o estado global
\n\nVariáveis e funções globais são o maior inimigo da refatoração. Comece encapsulando-as:
\n\n<?php\n// ANTES: função e variável global\n$db = mysql_connect('localhost', 'user', 'pass');\nfunction get_user($id) {\n global $db;\n $result = mysql_query("SELECT * FROM users WHERE id = $id", $db);\n return mysql_fetch_assoc($result);\n}\n\n// DEPOIS: classe com dependência explícita\nclass UserRepository {\n private PDO $pdo;\n \n public function __construct(PDO $pdo) {\n $this->pdo = $pdo;\n }\n \n public function findById(int $id): ?array {\n $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = ?');\n $stmt->execute([$id]);\n $user = $stmt->fetch();\n return $user ?: null;\n }\n}\n\n\nPasso 2: Separe a lógica da apresentação
\n\nO código legado típico contém SQL e lógica PHP diretamente no HTML. Use o padrão "Template Method" para separar:
\n\n<?php\n// ANTES: código espaguete no template\n?>\n<ul>\n<?php\n$result = mysql_query("SELECT * FROM products");\nwhile ($row = mysql_fetch_assoc($result)) {\n echo "<li>" . $row['name'] . " - " . $row['price'] . " R$</li>";\n}\n?>\n</ul>\n\n// DEPOIS: extração da lógica para um serviço\nclass ProductService {\n public function __construct(private ProductRepository $repo) {}\n \n public function getProductList(): array {\n return $this->repo->findAll();\n }\n}\n\n// No template