Apresentando a Regra de Adotação Segura e Progressiva de Tip

Posted on: April 09, 2026 01:03 AM

Posted by: Renato

Categories: Laravel PHP

Views: 66

Introducing Safe and Progressive Strict Type Adoption Rule

Apresentando a Regra de Adotação Segura e Progressiva de Tipos Estritos

A diretiva declare(strict_types=1) do PHP é uma ferramenta poderosa para prevenir bugs sutis. No entanto, a maioria dos projetos maduros e existentes não a utiliza de forma consistente, quando utiliza. Por quê? Porque adicioná-la automaticamente a todos os seus arquivos de uma vez fará sua aplicação explodir: espere milhares de erros. Isso deixa você com a tarefa de corrigir arquivos à mão, um por um, e dependendo de os membros da equipe lembrarem de adicioná-la em novos arquivos. Sem um processo seguro e automatizado, a adoção dificilmente se consolida.

Até agora. O novo SafeDeclareStrictTypesRector adiciona tipos estritos apenas a arquivos que já são seguros quanto ao tipo, tornando a adoção segura e progressiva finalmente possível e impedindo que o arquivo deixe de ser rigoroso no futuro.

Este é um post convidado por Caleb White, engenheiro e contribuidor de código aberto que colaborou com o Rector, PHPStan, framework Laravel e muitos outros projetos.

🧪 Nota: Este recurso ainda é experimental. Buscamos seu feedback em projetos reais. Algo quebrou quando não deveria? Informe-nos no GitHub.

O que é strict_types e por que você deve se importar?

Por padrão, o PHP coagirá valores escalares (bool, float, int, string, null) se houver uma incompatibilidade de tipo. Por exemplo, passar um bool para uma função que espera uma string o converterá silenciosamente em uma string:

PHP

<?php
function greet(string $name): string {
    // faz algo
}

greet(true); // O PHP converte silenciosamente para "1" sem aviso ou erro

Esse comportamento "prestativo" pode mascarar bugs sérios; no exemplo acima, passar true para um método que espera um nome em string é provavelmente um erro de lógica que precisa ser corrigido, mas que poderia passar despercebido.

A tipagem estrita evita essa coerção silenciosa lançando um TypeError se os tipos não coincidirem. Para usar, coloque declare(strict_types=1); no topo do seu arquivo e o PHP forçará a correspondência exata de tipos:

PHP

<?php 
declare(strict_types=1);

function greet(string $name): string {
    // faz algo
}

greet(true); // TypeError: must be of type string, bool given

// Se você realmente precisar coagir valores, use casts para ser explícito e indicar intenção
greet((string) $someBool);

Claro, alguns podem argumentar contra a tipagem estrita; que não gostam de ter que ser rígidos o tempo todo e converter valores para o tipo correto (se você está tendo que converter o mesmo valor de um lado para o outro várias vezes, provavelmente está fazendo algo errado). Mas a realidade é que a tipagem estrita elimina completamente uma certa classe de bugs que, de outra forma, passariam despercebidos, e torna a coerção de tipos explícita, intencional e visível.

Aqui estão pontos importantes sobre o strict_types:

  • Ele é definido apenas para declarações de tipos escalares, o que significa que só é aplicado em:

    • Argumentos passados para funções, métodos e construtores.

    • Declarações de retorno (return).

    • Atribuições de propriedades.

  • A única exceção é que um valor int passará em uma declaração de tipo float.

  • Ele tem escopo de arquivo, o que significa que um arquivo com strict_types=1 ainda pode incluir (include ou require) um arquivo que não seja estrito.

  • Ele afeta apenas o código de chamada, portanto, uma função pode ser chamada de forma não estrita se a chamada for feita a partir de um arquivo não estrito, mesmo que a função esteja definida em um arquivo estrito.

Uma História de Terror da Vida Real

Na minha empresa, aprendemos essa lição da maneira mais difícil. Alguém da nossa equipe estava argumentando contra tipos estritos e comentou: "Nunca tive um bug que tipos estritos teriam evitado". Menos de um mês depois, o mesmo indivíduo refatorou um código e acidentalmente introduziu exatamente esse tipo de bug.

💥 Nossos números de fabricação ficaram subitamente errados.

Meu gerente e eu passamos dois dias inteiros rastreando o problema. Sem exceções. Sem erros ou avisos nos logs. O diff parecia inocente, revisei o código da última versão várias vezes antes de finalmente encontrar o culpado: um método aceitava um int em vez de um float. 😬 A refatoração coagiu silenciosamente um comprimento decimal para um número inteiro: por exemplo, 4,5 polegadas tornaram-se 4 polegadas. Isso cascateou por vários cálculos e, por fim, causou estragos em nosso sistema.

Se aquele único arquivo tivesse declare(strict_types=1), teríamos visto um TypeError imediatamente, em vez de queimar quatro dias de tempo de engenharia.

O PHP depreciou a coerção implícita de float para inteiro desde o PHP 8.1, pois resulta em perda de precisão. No entanto, esses avisos de depreciação ainda podem ser ignorados ou enviados para um arquivo de log que pode não ser visto até que seja tarde demais.

O Problema da Adoção

Se os tipos estritos são tão valiosos, por que nem todos os utilizam? A resposta é simples: ativar tipos estritos em uma base de código madura existente é doloroso.

Ferramentas existentes como o DeclareStrictTypesRector ou a regra declare_strict_types do PHP-CS-Fixer simplesmente adicionam a diretiva a cada arquivo indiscriminadamente: uma abordagem de tudo ou nada. Em uma base de código grande, isso pode introduzir milhares de TypeErrors instantaneamente.

Nenhuma equipe quer:

  1. Corrigir toneladas de erros de tipo em centenas ou milhares de arquivos.

  2. Correr o risco de introduzir bugs em produção alterando o comportamento.

  3. Gastar semanas ou meses em uma "refatoração" que os stakeholders veem como entrega de valor zero para o negócio.

Assim, a adoção de tipos estritos estagna. As equipes sabem que deveriam usá-los, mas o caminho parece impossível. E mesmo com as melhores intenções, as equipes raramente são unificadas: alguns desenvolvedores defendem os tipos estritos, outros são indiferentes e todos ocasionalmente esquecem. Depender da disciplina manual de toda uma equipe simplesmente não escala.

Apresentando o SafeDeclareStrictTypesRector

O novo SafeDeclareStrictTypesRector adota uma abordagem fundamentalmente diferente: ele só adiciona declare(strict_types=1) a arquivos que já são seguros quanto ao tipo.

Em vez de adicionar cegamente a declaração em todos os lugares e quebrar as coisas, ele analisa cada arquivo para garantir que a ativação dos tipos estritos não mudará nenhum comportamento em tempo de execução. Se um arquivo lançasse um TypeError após a adição dos tipos estritos, o Rector o ignora completamente.

Como Funciona

Para cada arquivo, a regra examina todos os lugares onde a coerção de declaração de tipo poderia ocorrer:

  • Chamadas de função/método: todos os argumentos são compatíveis com os tipos dos parâmetros?

  • Declarações de retorno: todos os valores retornados são compatíveis com o tipo de retorno declarado?

  • Atribuições de propriedade: todos os valores atribuídos são compatíveis com as propriedades tipadas?

Para cada um destes, ele usa a inferência de tipos do PHPStan para verificar se os tipos de valores reais são estritamente compatíveis com os tipos declarados. Somente se cada ponto de coerção de tipo passar, o Rector adiciona a declaração.

PHP

<?php
// Este arquivo recebe strict_types porque já é seguro
function greet(string $name): string {
    // ...
}
echo greet("Mundo"); // String passada para parâmetro string: seguro!

PHP

<?php
// Este arquivo é IGNORADO porque depende de coerção de tipo
function setQuantity(int $quantity): void {
    // ...
}
setQuantity("3"); // String passada para parâmetro int: inseguro!

Conservador por Design

O verificador é intencionalmente conservador. Se não puder ter 100% de certeza de que um arquivo é seguro, ele o ignora:

  • Chamadas de métodos dinâmicos onde a reflexão não pode ser resolvida? Pula.

  • Desempacotamento de argumentos com ...$var? Pula.

  • Tipos mixed que poderiam ser qualquer coisa? Pula.

Isso significa que você pode não ter tipos estritos adicionados em todos os arquivos que poderiam tê-los, mas você nunca terminará com um arquivo quebrado.

Adoção Progressiva Tornada Possível

O verdadeiro poder do SafeDeclareStrictTypesRector é que ele permite a adoção progressiva:

  1. Rode o Rector: arquivos seguros recebem declare(strict_types=1) automaticamente.

  2. Esses arquivos agora estão protegidos contra futuros bugs de coerção de tipo.

  3. O PHPStan capturará quaisquer novas violações, impedindo que esses arquivos voltem a ser não estritos.

  4. Corrija os arquivos restantes incrementalmente conforme o tempo permitir.

  5. Reexecute o Rector periodicamente para capturar arquivos que se tornaram seguros recentemente (preferencialmente em um pipeline de CI).

Essa regra também funciona em conjunto com outras regras do Rector. O Rector possui regras que adicionam tipos de parâmetros, tipos de retorno e até fazem o cast de argumentos para o tipo correto. À medida que essas regras são executadas, arquivos que antes eram inseguros tornam-se seguros. Uma vez que um arquivo é totalmente seguro quanto ao tipo, o SafeDeclareStrictTypesRector adicionará automaticamente a declaração.

Isso cria um ciclo virtuoso: o Rector adiciona tipos e casts, os arquivos tornam-se "strict-safe" e o PHPStan evita regressões. Sua base de código torna-se gradualmente mais segura ao longo do tempo com o mínimo de esforço manual.

Em nossa aplicação corporativa, a primeira execução adicionou declare(strict_types=1) a mais de 1.500 arquivos: completamente automático e com risco zero de quebra. São 1.500 arquivos agora protegidos contra a exata classe de bug que nos custou dois dias de depuração. 💪

Experimente Você Mesmo

Adicione a regra à sua configuração do Rector (rector.php):

PHP

use Rector\Config\RectorConfig;
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\SafeDeclareStrictTypesRector;

return RectorConfig::configure()
    ->withRules([
        SafeDeclareStrictTypesRector::class,
    ]);

Em seguida, execute o Rector: veja como os arquivos seguros recebem automaticamente a diretiva, enquanto os arquivos inseguros permanecem intocados. Sem quebras. Sem riscos. Apenas melhoria automática.

Conclusão

Tipos estritos não deveriam ser uma escolha de tudo ou nada. Com o SafeDeclareStrictTypesRector, você pode adotar o declare(strict_types=1) de forma progressiva, automática e segura.

Cada arquivo que recebe tipos estritos é mais um arquivo protegido contra bugs silenciosos de coerção de tipo. Esses bugs podem custar dois dias de depuração como custaram para nós, ou podem custar muito mais.

Comece a proteger sua base de código hoje. 🛡️

Fonte: https://getrector.com/blog/introducing-safe-and-progressive-strict-type-adoption-rule#content-what-is-stricttypes-and-why-should-you-care


1

Share

Donate to Site


About Author

Renato

Developer

Add a Comment
Comments 0 Comments

No comments yet! Be the first to comment

Blog Search


Categories

Laravel (227) PHP (151) linux (124) Variados (110) Dicas (58) ubuntu (58) developer (48) postgresql (45) database (44) sql (42) Docker (32) front-end (31) mysql (31) devops (26) webdev (24) programming (23) aws (19) tecnologia (19) eloquent (19) dba (18) OUTROS (17) backend (16) laravelphp (16) debian (12) dev (12) reactjs (10) 100DaysOfCode (10) git (10) react (10) nginx (9) inteligencia-artificial (9) PHP Swoole (9) node (9) javascript (9) linux-tools (8) Architecture (8) vue (7) github (7) ciencia (7) nodejs (6) api (6) vscode (6) webservice (6) jwt (6) vim (6) windows (6) arquitetura (6) authentication (5) ia (5) reactnative (5) rest (5) DevSecOps (5) servers (5) apache (5) macox (5) s3 (5) Kubernetes (4) gitlab (4) opensource (4) mariadb (4) jenkins (4) shell (4) mongodb (4) angular (4) autenticacao (4) wsl (4) Swoole (4) lets-encrypt (4) query (4) Raspberry (4) angularjs (4) inteligenciadedados (4) Padrao de design (4) artigo (4) google (4) npm (4) openai (4) js (3) mysqli (3) Black Hat (3) RabbitMQ (3) educacao (3) intel (3) CMS (2) sail (3) script (3) performance (3) json (3) authorization (3) phpswoole (3) ddd (3) blade (3) terminal (3) log (3) mac (3) fedora (3) containers (3) ssh (3) bash (3) hardware (3) tests (3) macos (3) web (2) jobs (3) websocket (3) db (3) politica (3) Curisidades (2) Solid (2) zsh (2) Go (2) BigLinux (2) POO (2) LazyVim (2) gource (2) Python (2) Oauth2 (2) android (2) unix (2) magento (2) iot (2) ffmpeg (2) combustivel (2) webhook (2) microservices (2) bancodedados (2) tailwind (2) homeOffice (2) html (2) openswoole (2) artificialintelligence (2) security (2) auth (2) cron (2) phpunit (2) kube (2) multiple_authen (2) policia (2) neovim (2) golang (2) noticias (2) livros (2) Transcribe (2) ElonMusk (2) redis (2) claude (2) ArchLinux (2) java (2) saude (1) seguranca (2) phpfpm (2) autorizacao (2) monitoring (2) laptop (2) gnome (2) powerbi (2) telefonia (2) nvm (2) imagick (2) maps (2) colors (2) Passport (2) JQuery (2) front (1) wine (1) covid19 (0) services (1) phpjasper (1) models (1) kali-linux (1) geojson (1) yarn (1) picpay (1) Monolith (1) banco (1) PNPM (1) Desenvolvedor (1) Structurizr (1) symfony (1) presenter (1) lider (1) guard (1) tensorflow (1) bootstrap (1) nuance (1) historia (1) dropbox (1) traefik (1) bug (1) akitando (1) llm (1) htm (1) transformers (1) cavalotroia (1) odd (1) m1 (1) Error (1) cinnamon (1) repmgr (1) federal (1) ruby (1) AppSec (1) orm (1) ArquiteturaDeSoftware (1) Passwordless (1) memcached (1) flow (1) compression (1) athena (1) Migration (1) workflow (1) cqrs (1) kitematic (1) geospacial (1) yeshua (1) data (1) sonarqube (1) Axios (1) pipelines (1) Mozilla (1) kvm (1) GitOps (1) sqlite (1) podcast (1) n8n (1) LaravelFilament (1) God (1) DesenvolvimentoProfissional (1) sw (1) bigtech (1) postgres (1) NoCookies (1) LeetCode (1) governancadedados (1) prf (1) nosql (1) Lideranca (1) Hackers (1) Bots (1) pytorch (1) nuxt (1) liquid (1) ec2 (1) transaction (1) c4 (1) rancher (1) algoritimo (1) Observability (1) Elasticsearch (1) translate (1) certbot (1) Oh My Zsh (1) ibm (1) escopos (1) usb (1) ckeditor (1) API_KEY_GOOGLE_MAPS (1) Manjaro (1) vicuna (1) coding (1) rust (1) markdown (1) JasperReports (1) Fibonacci (1) community (1) Samurai (1) payment (1) messaging (1) Jesus (1) flutter (1) militar (1) fullsta (1) smartphones (1) automacao (1) Monitor (1) zend (1) spaceship (1) PKCE (1) l2tp (1) Glacier (1) laraveloctane (1) Deus (1) binaural (1) gpt (1) bolsonaro (1) privacidade (1) linkedin (1) documentation (1) brain (1) adb (1) nvidia (1) host (1) ecommerce (1) c4-models (1) altadisponibilidade (1) octane (1) lucena (1) http (1) TypeScript (1) chatgpt (1) idiomas (1) eventdrive (1) uuid (1) restfull (1) aplicativo (1) optimization (1) mapas (1) Fetch (1) collections (1) RustLang (1) matematica (1) Filament (1) compactar (1) paypal (1) microg (1) forcas armadas (1) cor (1) auth (1) modelagemdedados (1) k8s (1) gasolina (1) wsl2 (1) csv (1) soap (1) piada (1) KubeCon (1) zorin-os (1) spring-boot (1) backup (1) playwright (1) Deepin (1) storage (1) benchmark (1) networking (1) Swoole (1) biologia (1) node-red (1) LETSENCRYPT (1) Grunt (1) Diagramas (1) boot (1) haru (1) dracula (1) TrabalhoEmEquipe (1) Brasil (1) queue (1) agi (1) llama (1) hotfix (1) economia (1) transcription (1) cache (1) Amazon (1) October (1) lumen (1) Hyperf (1) replication (1) faceapp (1) vala (1) cloudstack (1) rpi (1) apple (1) oracle (1) iode (1) ffaa (1) vpn (1) MeioAmbiente (1) firefox (1) composer (1) scheduling (1) Asahi (1) pendrive (1) microservice (1) front (1) OOD (0) controllers (0)

New Articles



Get Latest Updates by Email