Hidrasi objek tampak seperti masalah yang sudah teratasi sampai Anda mulai mengukurnya. Anda mengambil sebuah baris dari database, memetakan array tersebut ke sebuah objek, dan selesai. Sebagian besar dari kita menganggapnya sebagai urusan teknis di balik layar—tidak terlihat, tidak menarik, dan dianggap sudah cukup cepat. Lalu suatu hari Anda melakukan profiling pada sebuah batch job atau queue worker dan menyadari bahwa sebagian besar waktu CPU habis terbuang di dalam mapper. Kesadaran itulah yang memicu lahirnya HydraType, sebuah hydrator yang dibangun berdasarkan satu aturan keras kepala: sebuah class tidak boleh menanggung beban fitur yang tidak digunakan oleh propertinya.
Jika sebuah field adalah string biasa yang tidak memerlukan transformasi apa pun, kode yang dihasilkan harus terlihat seperti ditulis secara manual oleh manusia. Penugasan langsung (direct assignment). Tanpa loop, tanpa pipeline, tanpa reflection.
Apa Biaya Sebenarnya dari Hidrasi
Pada pandangan pertama, mengubah ['name' => 'Alice', 'age' => 30] menjadi sebuah objek User tampak sepele. Masalah dimulai ketika Anda menginginkan fleksibilitas. Kebanyakan hydrator serbaguna mengandalkan reflection untuk memeriksa class pada saat runtime. Mereka membangun peta metadata, melakukan koersi tipe, dan menyelesaikan graf objek bersarang. Mereka juga sangat menyukai pipeline. Setiap nilai harus melewati serangkaian mutator, assertion, dan transformer, meskipun rangkaian tersebut kosong. Struktur loop itu sendiri menambah overhead.
Mengambil beberapa lusin record mungkin tidak akan membuat Anda menyadarinya. Namun, aplikasi PHP modern secara rutin memproses ribuan pesan antrean, mengimpor set CSV yang masif, atau menghidrasi set hasil yang dalam dari Elasticsearch. Dalam skenario tersebut, sebuah mapper yang membuang bahkan hanya beberapa mikrodetik per field akan menjadi hambatan (bottleneck) yang nyata. Seribu objek dengan masing-masing delapan field akan berlipat ganda menjadi beban yang sangat terasa.
Filosofi Zero-Overhead
Ide sentral di balik HydraType adalah isolasi fitur. Konversi tipe, hidrasi objek bersarang, dan assertion semuanya didukung, namun tidak ada yang bersifat wajib. Jika sebuah properti tidak membutuhkan apa pun selain salinan langsung dari array ke objek, writer yang dihasilkan hanya akan berisi hal tersebut. Tidak ada pipeline bersama yang memaksa sebuah field skalar biasa untuk mengantre di belakang validator yang tidak dibutuhkannya.
Ini lebih sulit dicapai daripada kedengarannya. Banyak library menggunakan satu jalur eksekusi tunggal untuk setiap field karena hal itu menjaga codebase tetap kecil dan seragam. HydraType mengambil pendekatan sebaliknya. Ia menghasilkan class PHP yang unik untuk setiap target DTO, mengeluarkan operasi yang secara spesifik dibutuhkan oleh class tersebut. Kompleksitas menjadi bersifat opt-in, bukan beban menyeluruh pada setiap properti.
Bagaimana Kecepatan Itu Tercipta
Empat pilihan konkret membedakan HydraType dari alat berbasis reflection generik maupun pendekatan berbasis kode yang dihasilkan lainnya.
1. Hasilkan Kode Sekali, Jalankan Selamanya
HydraType memeriksa class target Anda satu kali saja, lalu menulis class PHP khusus yang disesuaikan dengan bentuk persisnya. Jika DTO Anda berisi string publik $name, int $status, dan DateTime privat $createdAt, writer yang dihasilkan sudah mengetahui semua ini sejak awal. Tidak ada reflection yang berulang, tidak ada parsing string, dan tidak ada pembangunan metadata yang lambat selama runtime. Setelah OPCache mengompilasi file yang dihasilkan, Hydrator tersebut tidak dapat dibedakan dari PHP yang ditulis secara manual.
2. Hilangkan Pipeline Kosong
Kebanyakan hydrator menyusun pekerjaan mereka di sekitar pipeline saat runtime. Mereka mengelola sebuah array berisi callable—mutator, validator, transformer—dan melakukan iterasi pada setiap nilai. Bahkan ketika array tersebut kosong, foreach atau array_reduce tetap dieksekusi. HydraType menghilangkan hal ini sepenuhnya. Selama proses pembuatan kode, ia memeriksa apa yang sebenarnya dibutuhkan oleh sebuah properti. Jika daftar operasi kosong, ia akan mengeluarkan penugasan biasa seperti $object->name = $data['name'];. Runtime tidak pernah melakukan iterasi apa pun, karena generator sudah melakukan pemikirannya sebelumnya.
3. Gunakan Closure Scoping untuk Menghilangkan Penulisan Reflection
Properti private adalah masalah klasik bagi mapper eksternal. Jalan keluar yang biasa digunakan adalah ReflectionProperty::setValue(), tetapi metode tersebut membawa beban berat dibandingkan dengan akses properti secara langsung. HydraType menghindarinya dengan menggunakan Closure::bind. Writer yang dihasilkan berisi closure yang dibatasi (scoped) ke class target, yang memungkinkan mereka menyentuh properti private dan protected secara langsung tanpa reflection. Pengikatan (binding) terjadi satu kali saat konstruksi; setelah itu, closure berjalan dengan kecepatan yang mendekati native.
4. Gunakan Kembali Writer
Beberapa library menginstansiasi strategi atau graf reflection baru untuk setiap objek yang mereka hidrasi. HydraType membuat writer-nya satu kali, lalu menggunakan kembali instance tersebut untuk ribuan objek. Biaya per objek turun ke tingkat minimum, yaitu hanya menetapkan nilai properti dan mengembalikan hasilnya.
Angka-angkanya
Pada PHP 8.2, perbedaannya sangat mencolok:
- HydraType: 267,9 ns
- Ocramius GeneratedHydrator: 307,9 ns
- Symfony PropertyNormalizer: 8.499,0 ns
- Valinor: 10.755,2 ns
Symfony PropertyNormalizer dan Valinor adalah alat yang hebat, tetapi mereka bersifat generalis. PropertyNormalizer adalah bagian dari komponen serializer yang menangani deteksi format, normalizer, dan grafik objek yang mendalam. Valinor sangat ketat dalam hal pohon tipe (type trees) dan koersi (coercion). Kekuatan tersebut ada harganya. Dalam pengujian ini, keduanya kira-kira tiga puluh hingga empat puluh kali lebih lambat daripada HydraType. Bahkan Ocramius GeneratedHydrator, yang sudah menggunakan pembuatan kode (code generation), sedikit tertinggal karena perbedaan arsitektur seputar pipeline dan akses properti.
Konteks itu penting. Satu kueri database atau satu putaran HTTP (roundtrip) jauh melampaui semua angka ini. Jika Anda melakukan hidrasi pada tiga objek setelah sebuah kueri, mengejar nanodetik adalah pemborosan energi. Kesenjangan ini menjadi berarti saat Anda melakukan penskalaan. Sebuah proses batch yang menghidrasi lima puluh ribu rekaman, atau konsumen antrean (queue consumer) yang membangun kembali objek dari array cache, akan merasakan perbedaan antara 267 nanodetik dan sepuluh mikrodetik. Kalikan di seluruh kolom dan baris, dan pemetaan (mapper) yang lebih cepat dapat memangkas waktu beberapa detik dari sebuah pekerjaan tanpa mengubah logika bisnis apa pun.
Kesimpulan Utamanya
Pelajaran di sini bukanlah bahwa setiap proyek membutuhkan hydrator khusus. Melainkan bahwa pilihan arsitektur akan berakumulasi. Dengan menghasilkan kode yang hanya menyertakan apa yang Anda minta, HydraType menjaga properti biasa tetap cepat sambil tetap menawarkan jalan keluar (escape hatch) untuk properti yang kompleks. Konversi tipe dan objek bersarang (nested objects) tersedia saat Anda membutuhkannya, tetapi mereka tidak ikut membebani pemeriksaan performa untuk setiap string skalar pada objek tersebut.
Sebelum Anda beralih alat, lakukan profiling. Jika hidrasi tidak muncul dalam jejak (trace) dunia nyata Anda, tidak ada yang perlu diperbaiki. Namun jika Anda mendorong dataset besar melalui mapper generik dan melihat penggunaan CPU melonjak, ingatlah bahwa assignment PHP biasa masih ada. Terkadang kode tercepat hanyalah kode yang akan Anda tulis sendiri, dihasilkan sekali dan kemudian dilupakan.
