#desenvolvimento-de-software
#produto
Opinião

PHP 5.6 para PHP 8 ou reescrever do zero: as três medições que decidem por você

Migrar de PHP 5.6 para PHP 8 quase sempre custa menos que reescrever. Três medições (compatibilidade, dependências abandonadas e teste nos fluxos de receita) mostram se o seu caso

Por Victhor Araújo

Fundador da Revin. Engenheiro de formação, especialista em desenvolvimento de software e produtos digitais.

O código antigo costuma ser a única documentação viva das regras que sustentam o faturamento

O código antigo costuma ser a única documentação viva das regras que sustentam o faturamento

Dá para subir um sistema PHP 5.6 para o PHP 8, e na maior parte dos casos que chegam aqui isso sai bem mais barato que reescrever do zero. A parte que muda a conta é a outra metade da pergunta. Subir a versão do PHP e colocar Laravel no lugar do que já existe são duas tarefas diferentes, com riscos diferentes, e é a segunda que costuma engolir um trimestre inteiro.

Antes de escolher, meça três coisas, nesta ordem: quantos arquivos o PHP 8 realmente quebra, quantas das suas dependências não têm mais ninguém mantendo, e quanto do seu faturamento passa por um trecho de código que ninguém consegue rodar sem cliente do outro lado. Dá perto de dois dias de trabalho de um dev que já conhece o projeto. Barato perto do preço de errar essa escolha.

Banana prata, banana nanica e maçã

Meia hora de PHPCompatibility troca o "acho que é muita coisa" por uma contagem por arquivo

Meia hora de PHPCompatibility troca o "acho que é muita coisa" por uma contagem por arquivo

Teve um cliente que me perguntou se subir o MySQL 5 para o 7 era a mesma coisa que trocar para o Postgres. Respondi pela fruteira, porque ele não era técnico e fruteira todo mundo entende. MySQL 5 é banana prata, MySQL 7 é banana nanica, Postgres é maçã. As três são fruta, os três são banco SQL, e mesmo assim ninguém troca banana por maçã no meio da receita achando que vai dar na mesma.

Sair do PHP 5.6 para o 8 é trocar de banana. A linguagem é a mesma, quase toda a sintaxe que seu time escreveu continua válida, e o trabalho mora em incompatibilidades pontuais e em comportamento que mudou de resultado. Colocar Laravel dentro de um sistema que nasceu procedural é a maçã. O framework decide por onde a requisição entra, como a rota resolve, como o banco é acessado e onde a regra de negócio vive. Isso não é atualizar, é trocar a fundação com o prédio ocupado.

As duas coisas são possíveis. Só que quem promete as duas no mesmo cronograma normalmente entrega a primeira e passa o resto do ano na segunda.

Medição 1: quantos arquivos o PHP 8 quebra de verdade

Pare de discutir por impressão. Instale o PHPCompatibility no PHP_CodeSniffer, aponte para a versão de destino (8.2 ou 8.3) e rode no projeto inteiro. Em meia hora você sai do "acho que é muita coisa" para uma contagem de ocorrências por arquivo.

O resultado costuma surpreender para o lado bom. Num sistema de porte médio, o relatório aponta algo em torno de duas a quatro centenas de ocorrências, e boa parte concentrada em poucos arquivos. Quase tudo é mecânico: `each()` que sumiu, `create_function` que foi removido, chamada `mysql_` que já tinha morrido no 7, argumento passado por referência onde não pode mais. O Rector resolve um pedaço grande disso sozinho. O que sobra é trabalho chato de uma tarde, não projeto de trimestre.

O perigo mora no que não quebra. A comparação solta entre string e número mudou no PHP 8. No 5.6, `0 == "abc"` devolvia verdadeiro. No 8, devolve falso. Nada explode, nenhum log acende, o `if` apenas escolhe o outro caminho. Se aquele `if` decide desconto, faixa de frete ou permissão de acesso, sua regra de negócio mudou sem ninguém assinar embaixo.

Por isso a ordem importa. Primeiro você escreve teste de caracterização nos fluxos que geram dinheiro, congelando o comportamento atual mesmo quando ele é esquisito. Depois sobe a versão. Quem faz o contrário descobre a mudança pelo suporte, três semanas depois, num valor errado de nota fiscal.

Medição 2: o que o sistema depende e ninguém mais mantém

No caminho do meio o roteador entrega uma rota por vez, e o sistema roda partido por um tempo

No caminho do meio o roteador entrega uma rota por vez, e o sistema roda partido por um tempo

Segunda medição, meio dia de trabalho: `composer outdated --direct` e `composer audit`. Some a isso as extensões nativas que o servidor carrega, porque a mcrypt saiu do core no 7.2 e ainda aparece código de criptografia caseiro grudado nela.

É aqui que a decisão vira. Se as dependências diretas têm versão compatível com PHP 8, mesmo exigindo ajuste, existe caminho de atualização e ele é curto. Se o sistema está preso num framework que parou de receber correção há anos, alguma coisa vai ser reescrita de qualquer jeito. A diferença é que agora você sabe disso por medição, e pode reescrever a camada de entrada em vez do sistema inteiro. Reescrever o roteamento de um sistema é uma tarefa. Reescrever as regras de negócio de dez anos é outra, e é a que mata cronograma.

Um detalhe que encurta discussão de diretoria: rodar PHP 5.6 hoje significa rodar sem correção de segurança desde o fim de 2018. Isso não escolhe entre atualizar e reescrever. Tira do jogo a terceira opção, que costuma ser a favorita de todo mundo na reunião, a de deixar como está e olhar isso no ano que vem.

Medição 3: quanto do seu faturamento roda sem rede

A terceira medição não é cobertura de teste. Liste os quatro ou cinco fluxos que geram receita (cadastro do pedido, cálculo de preço, cobrança, emissão fiscal, integração com quem paga você) e pergunte uma coisa só sobre cada um: dá para rodar esse fluxo do começo ao fim, numa máquina limpa, sem cliente do outro lado?

O número que sai daí decide mais que qualquer discussão de stack. Sistema com fluxo de dinheiro reproduzível aguenta migração de versão tranquilo. Sistema em que a única forma de saber se a cobrança funcionou é esperar o boleto do dia seguinte não aguenta nem migração nem reescrita, porque nos dois casos você vai empurrar mudança no escuro.

E cuidado com o relatório bonito. Já abri projeto com cobertura alta em que os testes rodavam o método e não verificavam nada, sem um `expect` no meio. A métrica existia, a garantia não. Vale o mesmo raciocínio que uso quando alguém herda um sistema legado sem documentação: mede primeiro, escreve depois.

"Mas ninguém entende mais esse código"

Essa frase apareceu em quase todo comentário da thread que originou este texto, no TabNews, que juntou 35 comentários numa semana. Ela é verdadeira e é o pior argumento possível a favor de reescrever.

O código feio é a documentação viva das suas regras. Aquele `if` esquisito no cálculo de comissão é um acordo que alguém fechou com um parceiro em 2019 e nunca escreveu em lugar nenhum. Quando o time reescreve do zero, ele não reescreve o que está no código. Reescreve o que consegue entender do código, que é sempre menos. O resto reaparece como bug em produção, um por semana, durante meses. É o motivo de eu quase nunca aprovar reescrever um sistema do zero quando me perguntam.

Tem também a conta que ninguém coloca no slide. Reescrita congela o produto. Enquanto o time refaz o que já existe, o concorrente lança feature e o seu comercial vende o mesmo sistema de sempre. Com o custo de um squad em 2026, um trimestre inteiro sem entrega nova para o cliente é dinheiro que você paga duas vezes, na folha e no roadmap parado.

O caminho do meio, e o dia em que ele não serve

O que dá certo na maioria dos casos é fatiar em três movimentos, nesta ordem:

  1. Suba para PHP 8 com o código como está, feio do jeito que ele é, com teste de caracterização nos fluxos de dinheiro escritos antes. É a etapa mais barata e a que tira você do risco de segurança.
  2. Organize o que já existe sem trocar de fruta: Composer com autoload PSR-4, uma porta de entrada única, configuração fora do código e log de verdade. Isso é arrumação, não framework.
  3. Suba o Laravel ao lado, na mesma base de dados, e mande o roteador entregar uma rota por vez para ele. Cadastro novo nasce no Laravel, checkout antigo continua onde está até ter teste que sustente a mudança.

No terceiro movimento o sistema roda partido por um tempo, e isso incomoda todo desenvolvedor que gosta de coisa limpa. Aguente o incômodo. Software não fica pronto, e o estado partido é reversível a qualquer momento, coisa que uma reescrita de nove meses não é.

Agora o limite, porque conselho que só afirma não vale nada. Esse caminho não serve em três situações. Quando a dependência central do sistema não tem nenhuma versão que rode em PHP 8 e o fornecedor sumiu, você já está reescrevendo, só falta admitir. Quando o negócio mudou tanto que o sistema modela uma empresa que não existe mais, migrar versão só preserva um modelo errado com sintaxe nova. E quando a operação inteira cabe em umas oito telas, o custo de reescrever cai para semanas e a matemática vira, ainda que eu recomende medir antes de acreditar nessa contagem de telas, que sempre aumenta quando alguém abre o código.

Se você vai levar essa decisão para uma reunião esta semana, peça dois números antes de qualquer proposta: quantas ocorrências o PHPCompatibility aponta e quantas dependências diretas não têm versão para PHP 8. Se ninguém do seu time conseguir responder isso em dois dias, o problema não está na escolha entre migrar e reescrever. Está no fato de que ninguém ainda abriu o sistema para olhar.

Pronto para elevar o seu negócio?

Agendar uma reunião
Compartilhe
Link de compartilhamento LinkedinLink de compartilhamento XLink de compartilhamento WhatsappLink de compartilhamento Facebook

A cada quinze dias. As decisões técnicas que tomamos, e o que aprendemos.