Tipos estritos em todos os lugares
Spec: ISO 32000-2, §7.5.5 ISO 32000-2 §7.5.5 Evidence: Code-backed PHPStan: Level 10, no src baseline
Visão geral
Seção intitulada “Visão geral”O NextPDF executa o PHPStan no Level 10 sobre o código do motor sem nenhum baseline de supressão. Esta página explica por que “sem baseline” é uma decisão de design, e não um detalhe de ferramenta, e o que essa rigidez de fato traz para um pipeline cuja função é impedir o tratamento incorreto e silencioso de dados.
Por que isto importa
Seção intitulada “Por que isto importa”Na maioria das aplicações, a tipagem estrita é higiene. Em um motor de PDF, ela se aproxima de um mecanismo de correção. O formato é implacável. Espera-se que um leitor localize o conteúdo lendo o arquivo a partir do final, passando pelo trailer e pela tabela de referência cruzada, de modo que os offsets de byte gravados precisam ser exatos. Considere um tipo que se amplia silenciosamente para mixed, um int que silenciosamente vira uma string, ou um valor nullable que é desreferenciado sem verificação. Qualquer um deles pode produzir um arquivo que abre sem problemas em um visualizador e falha na validação em outro, semanas depois, sem nenhum stack trace apontando para a causa.
As falhas caras neste domínio são as silenciosas. A tipagem estrita, somada a um analisador estrito, é a forma como o motor converte uma classe de falhas silenciosas em tempo de execução em falhas ruidosas em tempo de build.
A versão resumida
Seção intitulada “A versão resumida”- O código do motor é analisado no PHPStan Level 10 — o nível mais rigoroso — verificado em
phpstan.neon.dist. - Não existe nenhum baseline de supressão de origem. A configuração mantém a análise do código em zero erros. Uma regressão faz o build falhar em vez de ser absorvida por um arquivo de ignorados em constante crescimento.
- As poucas entradas
ignoreErrorsexistentes são restritas, delimitadas por identifier e por path e justificadas individualmente na configuração (limites de soft-dependency entre pacotes e pontos de costura de teste com alvos de reflection) — elas não são um baseline em massa. - Um perfil estrito separado executa
level: maxe proíbe quaisquer novas entradas de ignorados, de modo que o código novo é mantido sob um padrão ainda mais rígido. - O efeito pretendido é pressão de design: código que não pode ser expresso de forma honesta quanto aos tipos não passa, então é redesenhado em vez de suprimido.
Como o NextPDF aborda isso
Seção intitulada “Como o NextPDF aborda isso”A diferença entre “usamos um analisador estrito” e “usamos um analisador estrito sem baseline” é justamente o ponto central, então vale a pena ser preciso.
Um baseline registra todas as violações existentes e instrui o analisador a ignorar exatamente essas violações. É uma forma pragmática de adotar análise estática em uma base de código legada, mas tem um custo. O baseline se torna um registro silencioso de dívida que o sistema de tipos concordou em não examinar. Novas violações do mesmo tipo podem se infiltrar ao lado das existentes. A promessa do analisador enfraquece de “este código está limpo quanto aos tipos” para “este código não está pior do que estava.”
O NextPDF não faz essa troca para o código do motor. A configuração fixa a análise do código em zero erros e ativa reportUnmatchedIgnoredErrors, de modo que até uma supressão obsoleta — uma que não corresponde mais a nada — faz o build falhar. Os ignorados restritos que permanecem são delimitados a um identifier de erro e a um arquivo específicos. Cada um traz uma explicação inline de por que o limite é intencional (por exemplo, o core programando para uma interface Pro/Enterprise da qual ele deliberadamente não depende de forma concreta). Um revisor pode ler cada um e avaliá-lo. Não há nenhuma lista opaca que saia de controle.
O fluxo que mantém isso honesto:
- Change proposed New or modified engine code.
- Level 10 analysis Strictest PHPStan level over src/, treatPhpDocTypesAsCertain on.
- Zero-error gate No source baseline; unmatched ignores also fail.
- Strict profile level: max; no new ignore entries permitted.
- Redesign, not suppress If it cannot be expressed honestly, the design changes.
treatPhpDocTypesAsCertain faz parte disso. As anotações PHPDoc são tratadas como verdade absoluta, de modo que um @param list<T> ou @return non-empty-string não é um comentário que o analisador simplesmente ignora. É uma promessa verificada. A anotação e o tipo em tempo de execução são forçados a concordar.
O que a evidência diz
Seção intitulada “O que a evidência diz”Esta página é Evidence: Code-backed . A configuração é a evidência:
phpstan.neon.distdefinelevel: 10,phpVersion: 80400, analisasrce não contém nenhuma chavebaseline:— não existe nenhumphpstan-baseline.neonpara a análise do código.- O mesmo arquivo define
treatPhpDocTypesAsCertain: trueereportUnmatchedIgnoredErrors: true, com uma nota inline de que a análise de código L10 está fixa em zero erros e qualquer regressão deve fazer o CI falhar. - As entradas
ignoreErrorsrestantes são cada uma delimitada poridentifiere, com frequência, porpath, com comentários explicando a justificativa de soft-dependency e de alvo de reflection — elas não são um baseline gerado em massa. phpstan-strict.neon.distherda essa configuração, eleva o nível paramaxe congela a lista de ignorados, de modo que nenhuma nova entrada pode ser adicionada sob o perfil estrito.
O ponto de vista dos padrões é direto. O motor deve produzir arquivos que um leitor consiga navegar a partir do trailer e da tabela de referência cruzada conforme Spec: ISO 32000-2, §7.5.5 ISO 32000-2 §7.5.5 . Offsets de byte exatos são um problema de tipo antes de serem um problema de serialização. Um offset é um inteiro que jamais pode se tornar silenciosamente outra coisa. Um pipeline que está limpo quanto aos tipos no Level 10 já removeu a maioria das formas pelas quais a aritmética pode dar errado silenciosamente.
Exemplo prático
Seção intitulada “Exemplo prático”A tipagem estrita fica mais visível quando uma regra de domínio é codificada como um tipo em vez de uma verificação em tempo de execução. O discriminador de conformidade responde a perguntas em nível de especificação com um match exaustivo, de modo que um caso não tratado é um erro de tipo, não um PDF incorreto:
declare(strict_types=1);
enum ConformanceMode: string{ case Plain = 'plain'; case PdfUa2 = 'pdfua2'; case PdfA4 = 'pdfa4';
/** @return 2|3|4|null */ public function pdfaPart(): ?int { return match ($this) { self::PdfA4 => 4, default => null, }; }}O @return 2|3|4|null não é documentação. Sob o
treatPhpDocTypesAsCertain, ele é verificado. Um caller que assume que o resultado é sempre um int recebe esse aviso em tempo de análise, antes que um único byte de um número de part de PDF/A não conforme seja escrito.
Equívoco comum
Seção intitulada “Equívoco comum”A armadilha é ler “sem baseline” como “por acaso, o código não tem violações.” Isso está invertido. A ausência de um baseline é a causa, não um resultado de sorte. Como não há onde estacionar uma violação, o código que produziria uma precisa ser escrito de outra forma. O Level 10 sem baseline de origem é uma restrição que molda o design, não um boletim que o descreve depois do fato.
Um segundo equívoco: achar que o punhado de entradas ignoreErrors é um baseline com outro nome. Não é. Um baseline é gerado em massa e opaco. Estas são escritas individualmente, delimitadas por identifier, explicadas e protegidas por reportUnmatchedIgnoredErrors, de modo que não podem ficar obsoletas despercebidas.
Limites e fronteiras
Seção intitulada “Limites e fronteiras”Esta página trata da análise do código do motor. A suíte de testes é analisada sob um escopo e uma configuração separados e deliberadamente distintos; “sem baseline” aqui é uma afirmação sobre src/, não uma alegação de que toda análise auxiliar no repositório seja livre de baseline. O PHPStan prova a solidez de tipos, não a correção comportamental. Ele não substitui a pirâmide de testes; apenas remove uma categoria de falha que, de outra forma, os testes teriam de perseguir. O nível exato, as flags e o conjunto de ignorados estão corretos na data de revisão desta página. A fonte autoritativa é sempre phpstan.neon.dist e phpstan-strict.neon.dist no repositório core.
A edição não altera esta disciplina. Toda edição é construída a partir do mesmo código Level 10:
| Edition | Availability |
|---|---|
| Core | O código do Core é analisado no Level 10 sem baseline de origem. |
| Pro | O Pro é construído sobre a mesma disciplina de código Level 10. |
| Enterprise | O Enterprise é construído sobre a mesma disciplina de código Level 10. |
Documentos relacionados
Seção intitulada “Documentos relacionados”- As fundações do PHP 8.4 — os recursos da linguagem dos quais o sistema de tipos depende.
- Erros como recurso — o que acontece com as falhas expostas pela tipagem estrita.
- O modelo de pipeline — a arquitetura que esta disciplina protege.
Glossário
Seção intitulada “Glossário”- PHPStan Level 10 — o nível de análise mais rigoroso, tratando valores sem tipo e com tipagem frouxa como erros em vez de avisos.
- Baseline — um registro gerado de violações existentes que o analisador é instruído a ignorar. O NextPDF não usa nenhum para o código do motor.
treatPhpDocTypesAsCertain— uma configuração do PHPStan que trata as anotações de tipo PHPDoc como fatos verificados, não como comentários consultivos.reportUnmatchedIgnoredErrors— uma configuração que faz o build falhar quando uma entrada de ignorados não corresponde mais a nada, evitando supressões obsoletas.- Pressão de design — o efeito de uma restrição que força o código a ser escrito de determinada forma, em oposição a uma verificação que apenas o mede.