Lewati ke konten

Tipe ketat, di mana pun

Spec: ISO 32000-2, §7.5.5 Evidence: Code-backed PHPStan: Level 10, no src baseline

NextPDF menjalankan PHPStan pada Level 10 di seluruh source engine tanpa baseline untuk penekanan. Halaman ini menjelaskan mengapa “tanpa baseline” adalah keputusan desain, bukan sekadar detail perkakas, serta apa yang sebenarnya diperoleh pipeline yang harus mencegah data salah ditangani tanpa terdeteksi dari disiplin ketat tersebut.

Pada kebanyakan aplikasi, pengetikan ketat adalah soal kebersihan kode. Pada engine PDF, hal itu lebih dekat ke mekanisme penjaminan kebenaran. Formatnya tidak memberi ampun. Reader diharapkan menemukan konten dengan membaca berkas dari bagian akhir, melalui trailer dan cross-reference table, sehingga byte offset dari writer harus tepat. Bayangkan tipe yang diam-diam melebar menjadi mixed, int yang tanpa terdeteksi berubah menjadi string, atau nilai nullable yang didereferensi tanpa pemeriksaan. Salah satu saja dari kondisi itu dapat menghasilkan berkas yang tampak terbuka baik-baik saja di satu viewer, tetapi gagal validasi di viewer lain, berminggu-minggu kemudian, tanpa stack trace yang menunjuk kembali ke penyebabnya.

Kegagalan paling mahal di domain ini adalah kegagalan yang tidak terdeteksi. Pengetikan ketat, bersama analyzer yang ketat, adalah cara engine mengubah satu kelas kegagalan runtime yang senyap menjadi kegagalan build-time yang jelas.

  • Source engine dianalisis pada PHPStan Level 10 — level paling ketat — dan diverifikasi di phpstan.neon.dist.
  • Tidak ada baseline penekanan untuk source. Konfigurasinya mengunci analisis source pada nol kesalahan. Regresi menggagalkan build alih-alih diserap ke dalam berkas ignore yang terus membengkak.
  • Segelintir entri ignoreErrors yang tersisa bersifat sempit, dibatasi per identifier dan path, serta dijustifikasi satu per satu di dalam konfigurasi (batas soft-dependency lintas-paket dan test seam yang menjadi target refleksi) — bukan baseline massal.
  • Profil ketat terpisah menjalankan level: max dan melarang penambahan entri ignore baru, sehingga kode baru dijaga pada standar yang lebih ketat lagi.
  • Efek yang dituju adalah tekanan desain: kode yang tidak dapat diekspresikan secara jujur dari sisi tipe tidak akan lolos, sehingga kode itu dirancang ulang alih-alih ditekan.

Perbedaan antara “kami menggunakan analyzer yang ketat” dan “kami menggunakan analyzer yang ketat tanpa baseline” adalah inti persoalannya, jadi perlu dibedakan dengan cermat.

Sebuah baseline mencatat setiap pelanggaran yang sudah ada dan meminta analyzer mengabaikan persis pelanggaran-pelanggaran itu. Ini adalah cara pragmatis untuk mengadopsi analisis statis pada basis kode lama, tetapi ada harganya. Baseline itu menjadi catatan utang senyap: sesuatu yang telah disetujui sistem tipe untuk tidak dilihat. Pelanggaran baru dengan jenis yang sama bisa terselip di samping pelanggaran yang sudah ada. Janji analyzer melemah dari “kode ini bersih dari sisi tipe” menjadi “kode ini tidak lebih buruk dari sebelumnya.”

NextPDF tidak mengambil trade-off itu untuk source engine. Konfigurasinya mengunci analisis source pada nol kesalahan dan mengaktifkan reportUnmatchedIgnoredErrors, sehingga bahkan penekanan yang usang — yang tidak lagi cocok dengan apa pun — akan menggagalkan build. Entri ignore sempit yang tersisa dibatasi pada identifier kesalahan dan berkas tertentu. Masing-masing memuat penjelasan inline tentang mengapa batas itu disengaja (misalnya, core yang memprogram terhadap interface Pro/Enterprise yang sengaja tidak dijadikannya dependensi konkret). Reviewer dapat membaca masing-masing dan menilainya. Tidak ada daftar buram yang bisa lepas dari pengawasan.

Alur yang menjaga hal ini tetap jujur:

  1. Change proposed New or modified engine code.
  2. Level 10 analysis Strictest PHPStan level over src/, treatPhpDocTypesAsCertain on.
  3. Zero-error gate No source baseline; unmatched ignores also fail.
  4. Strict profile level: max; no new ignore entries permitted.
  5. Redesign, not suppress If it cannot be expressed honestly, the design changes.
Bagaimana sebuah perubahan sampai ke source engine: perubahan yang tidak jujur dari sisi tipe tidak dapat melewati gerbang, sehingga dirancang ulang alih-alih ditekan.

treatPhpDocTypesAsCertain juga bagian dari disiplin ini. Anotasi PHPDoc diperlakukan sebagai fakta dasar, sehingga @param list<T> atau @return non-empty-string bukan sekadar komentar yang boleh diabaikan analyzer. Itu adalah janji yang diperiksa. Anotasi dan tipe runtime dipaksa untuk sepakat.

Halaman ini bersifat Evidence: Code-backed . Buktinya ada pada konfigurasi:

  • phpstan.neon.dist menetapkan level: 10, phpVersion: 80400, menganalisis src, dan tidak memuat kunci baseline: — tidak ada phpstan-baseline.neon untuk analisis source.
  • Berkas yang sama menetapkan treatPhpDocTypesAsCertain: true dan reportUnmatchedIgnoredErrors: true, disertai catatan inline bahwa analisis source L10 dikunci pada nol kesalahan dan setiap regresi harus menggagalkan CI.
  • ignoreErrors yang tersisa masing-masing dibatasi berdasarkan identifier dan sering kali path, dengan komentar yang menjelaskan alasan soft-dependency dan target refleksi — semuanya bukan baseline yang dihasilkan secara massal.
  • phpstan-strict.neon.dist mewarisi konfigurasi tersebut, menaikkan level menjadi max, dan membekukan daftar ignore sehingga tidak ada entri baru yang boleh ditambahkan di bawah profil ketat.

Dari sudut pandang standar, kaitannya langsung. Engine harus menghasilkan berkas yang dapat ditelusuri oleh reader dari trailer dan cross-reference table sesuai Spec: ISO 32000-2, §7.5.5 . Byte offset yang tepat adalah masalah tipe sebelum menjadi masalah serialisasi. Offset adalah integer yang tidak boleh diam-diam berubah menjadi apa pun yang lain. Pipeline yang bersih dari sisi tipe pada Level 10 telah menghilangkan sebagian besar cara aritmetika dapat keliru tanpa terdeteksi.

Pengetikan ketat paling terlihat ketika sebuah aturan domain dikodekan sebagai tipe alih-alih pemeriksaan runtime. Diskriminator konformansi menjawab pertanyaan tingkat spesifikasi dengan match yang menyeluruh, sehingga kasus yang tidak ditangani menjadi kesalahan tipe, bukan PDF yang salah:

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,
};
}
}

@return 2|3|4|null bukan dokumentasi semata. Di bawah treatPhpDocTypesAsCertain, hal itu diperiksa. Pemanggil yang mengasumsikan hasilnya selalu berupa int akan diberi tahu pada tahap analisis, sebelum satu byte pun dari nomor bagian PDF/A yang tidak konforman pernah ditulis.

Jebakannya adalah membaca “tanpa baseline” sebagai “kebetulan kode tidak memiliki pelanggaran.” Cara baca itu terbalik. Ketiadaan baseline adalah penyebabnya, bukan hasil yang kebetulan beruntung. Karena tidak ada tempat untuk menampung pelanggaran, kode yang akan menghasilkan pelanggaran harus ditulis dengan cara berbeda. Level 10 tanpa baseline pada source adalah batasan yang membentuk desain, bukan rapor yang menggambarkannya setelah kejadian.

Kesalahpahaman kedua: bahwa segelintir entri ignoreErrors adalah baseline dengan nama lain. Mereka bukan. Sebuah baseline dihasilkan secara massal dan buram. Entri-entri ini ditulis satu per satu, dibatasi per identifier, dijelaskan, dan dijaga oleh reportUnmatchedIgnoredErrors sehingga tidak dapat membusuk tanpa terdeteksi.

Halaman ini membahas analisis source engine. Test suite dianalisis di bawah ruang lingkup dan konfigurasi terpisah yang sengaja berbeda; “tanpa baseline” di sini adalah pernyataan tentang src/, bukan klaim bahwa setiap analisis tambahan di dalam repositori bebas dari baseline. PHPStan membuktikan kesahihan tipe, bukan kebenaran perilaku. Ia tidak menggantikan piramida pengujian; ia hanya menghilangkan satu kategori kegagalan yang, jika tidak demikian, harus dikejar oleh tes. Level, flag, dan kumpulan ignore tersebut akurat per tanggal peninjauan halaman ini. Sumber otoritatifnya selalu phpstan.neon.dist dan phpstan-strict.neon.dist di repositori core.

Edisi tidak mengubah disiplin ini. Setiap edisi dibangun dari source Level 10 yang sama:

Level 10 source analysis — edition availability
Edition Availability
Core Source Core dianalisis pada Level 10 tanpa baseline untuk source.
Pro Pro dibangun di atas disiplin source Level 10 yang sama.
Enterprise Enterprise dibangun di atas disiplin source Level 10 yang sama.
  • PHPStan Level 10 — level analisis paling ketat, yang memperlakukan nilai tanpa tipe maupun bertipe longgar sebagai kesalahan alih-alih peringatan.
  • Baseline — catatan pelanggaran yang sudah ada, yang kemudian diminta agar diabaikan oleh analyzer. NextPDF tidak menggunakannya sama sekali untuk source engine.
  • treatPhpDocTypesAsCertain — pengaturan PHPStan yang memperlakukan anotasi tipe PHPDoc sebagai fakta yang diperiksa, bukan komentar yang bersifat anjuran.
  • reportUnmatchedIgnoredErrors — pengaturan yang menggagalkan build ketika sebuah entri ignore tidak lagi cocok dengan apa pun, mencegah penekanan yang usang.
  • Tekanan desain — efek dari sebuah batasan yang memaksa kode ditulis dengan cara tertentu, berlawanan dengan sebuah pemeriksaan yang hanya mengukurnya.