O que o PHP moderno mudou na prática

Durante anos o PHP carregou a fama de linguagem de script sem contrato. A linha 8 mudou esse quadro: tipos em propriedades, enums, classes readonly, promoção de construtor, match, argumentos nomeados e union types. Em um sistema corporativo o efeito não é estético. Tipo explícito vira contrato verificável, e ferramentas de análise estática (PHPStan, Psalm) apontam erro antes do deploy. Um declare(strict_types=1) no topo do arquivo elimina a coerção silenciosa que só aparece quando alguém digita a matrícula com máscara e o código aceita.

Enums merecem destaque porque resolvem um problema recorrente de retaguarda: status de pedido, de nota fiscal ou de proposta como string solta espalhada pelo código. Com enum, o status é um conjunto fechado, o match obriga a tratar todos os casos e qualquer valor novo quebra a análise em vez de quebrar a produção.

O modelo de execução também importa para quem decide. Em PHP-FPM cada requisição nasce e morre isolada, sem estado compartilhado entre chamadas, o que simplifica o raciocínio sobre vazamento de memória e facilita escala horizontal atrás de um balanceador. Com Opcache configurado, o custo de interpretar o código a cada requisição praticamente desaparece.

O que o Laravel entrega pronto e o que continua sendo responsabilidade do time

  1. Container e injeção de dependências: integrações com ERP, gateways e serviços internos entram por contrato, o que permite substituir a implementação em teste.
  2. Form Requests: validação de entrada declarativa, com regras versionadas junto ao código em vez de espalhadas em condicionais.
  3. Policies e Gates: alçada de aprovação e permissão por unidade passam a ser regra testável, não checagem manual na tela.
  4. Filas (Redis, SQS ou a própria tabela): chamadas a sistemas legados saem do ciclo da requisição, com retry e timeout explícitos.
  5. Migrations e seeders: o esquema do banco é versionado e revisado como código.
  6. Testes de feature com banco real: cobrem o fluxo inteiro, de rota a persistência.
  7. Scheduler com trava: rotinas noturnas de conciliação não rodam duas vezes por engano em múltiplas instâncias.

O que o framework não resolve: modelagem. Eloquent é conveniente para CRUD e caro em relatórios; lazy loading ingênuo gera N+1 na listagem de pedidos com centenas de itens. Regra de negócio em controller ou em model gordo é dívida que o framework não impede.

Um caso concreto: distribuidora com alçada de desconto

Uma distribuidora de autopeças com equipe interna enxuta mantinha um portal de pedidos em que o desconto era aprovado por e-mail. As regras: até certo percentual o supervisor libera, acima disso entra a gerência regional e, em outro patamar, a diretoria comercial. Não havia registro confiável de quem aprovou o quê.

Na reescrita em Laravel, a alçada virou Policy, o cálculo virou serviço com teste unitário, a validação do pedido ficou em Form Request e o envio ao ERP virou job em fila com idempotência (a chave do pedido evita duplicidade em retry). O portal responde mesmo com o ERP lento, e a trilha de auditoria passou a existir por construção. O ganho não veio do framework: veio de colocar a regra em um lugar testável.

Na prática

  • Aplique strict_types=1 nos arquivos novos e trate os antigos conforme for mexendo.
  • Suba o nível do PHPStan aos poucos; cada nível revela um contrato quebrado.
  • Troque strings de status por enum e deixe o match obrigar o tratamento de todos os casos.
  • Valide entrada em Form Request, nunca confiando apenas na tela.
  • Coloque autorização em Policy, não em condicional de controller.
  • Isole integração externa em job com timeout, retry e chave de idempotência.
  • Antes de publicar uma listagem, revise N+1 olhando o log de queries.
  • Mantenha regra de negócio em classe de serviço coberta por teste de feature.