Site icon SUSANTOKUN

Fitur Baru PHP 8.5 yang Bikin Kode Lebih Rapi

PHP 8.5 sudah resmi dirilis sejak 20 November 2025, tapi banyak project di Indonesia masih bertahan di 8.2 atau 8.3. Alasan yang paling sering muncul sama: takut ada yang rusak. Padahal perubahan di PHP 8.5 justru menyentuh cara menulis kode sehari-hari — ada operator pipe, clone() yang kini berperilaku seperti fungsi, dan penanda bahwa nilai balik sebuah fungsi tidak boleh dibuang begitu saja. Artikel ini membahas fitur-fitur itu dengan contoh yang bisa langsung dicoba.

Rilis stabil 8.5.0 keluar 20 November 2025. Sampai artikel ini ditulis, cabang 8.5 sudah menerima patch pemeliharaan hingga 8.5.12 (21 Oktober 2026), dan sebagian besar patch tersebut bertanda keamanan. Artinya 8.5 sudah cukup matang. PHP 8.5 juga tidak memaksa kamu menulis ulang apa pun: semua fitur di bawah ini aditif, jadi kode yang jalan di 8.4 tetap jalan kecuali bagian yang sudah ditandai deprecated.

Pipe Operator: Merangkai Fungsi dari Kiri ke Kanan

Fitur ini paling banyak dibicarakan. Sebelumnya, merangkai beberapa fungsi berarti kamu menulis pemanggilan bersarang dan membacanya dari dalam ke luar: count(array_filter(getUsers(), fn ($u) => $u->isAdmin)). Dengan pipe (|>), urutan eksekusi mengikuti arah baca:

<?php
$jumlahAdmin = getUsers()
    |> (fn (array $users) => array_filter($users, fn ($u) => $u->isAdmin))
    |> count(...);

Nilai di sebelah kiri dikirim sebagai satu-satunya argumen ke callable di sebelah kanan. Tanda (...) adalah sintaksis first-class callable yang sudah ada sejak PHP 8.1; itulah sebabnya count(...) bisa ditulis begitu tanpa closure tambahan.

Batasan yang perlu diingat: sisi kanan wajib berupa callable yang menerima tepat satu parameter. Fungsi dengan dua argumen wajib — misalnya str_replace() — tidak bisa dipipe langsung, dan kalau dipaksa akan gagal seperti pemanggilan dengan argumen kurang. Untuk kasus itu, bungkus dengan arrow function.

Precedence, Batasan, dan Kapan Pipe Tidak Cocok

Pipe bersifat left-associative: sisi kiri dievaluasi lebih dulu, lalu hasilnya diteruskan. Operator ini mengikat setelah operasi matematika, tetapi sebelum perbandingan. Jadi 5 + 2 |> someFunc(...) sama dengan (5 + 2) |> someFunc(...), sementara 'beep' |> strlen(...) == 4 membandingkan hasil pipe dengan angka 4. Pipe juga berjalan sebelum ??, sehingga nilai default berlaku untuk hasil akhir seluruh rantai — bukan untuk tiap langkah di dalamnya.

Kalau sisi kanan berisi ternary atau ekspresi yang memilih callable, tanda kurung wajib dipakai. Tanpa kurung, parser membaca urutan yang berbeda, dan errornya bukan error sintaksis sehingga lebih menjengkelkan saat debugging.

Soal performa, pipe diterjemahkan di level compiler: callable gaya fungsi, method, atau static method dikompilasi menjadi pemanggilan langsung, jadi praktis tanpa overhead. Yang menambah kerja hanya arrow function pembungkus.

Pipe juga bukan pengganti semua pemanggilan fungsi. Untuk dua langkah saja, variabel biasa lebih mudah di-debug. Pipe kurang nyaman kalau tiap langkah butuh argumen tambahan, sebab hampir semua langkah jadi arrow function satu baris. Di tim yang servernya masih 8.4, rekan yang belum upgrade tidak bisa menjalankan kode itu.

Contoh Praktis: Membuat Slug di Satu Rantai

Kasus paling sering di aplikasi nyata: merapikan input teks. Alur membuat slug biasanya terdiri dari empat langkah kecil: potong spasi, kecilkan huruf, ganti karakter non-alfanumerik dengan tanda hubung, lalu rapikan tanda hubung di ujung. Empat langkah itu bisa ditulis sebagai satu rantai:

<?php
$slug = $judul
    |> trim(...)
    |> strtolower(...)
    |> (fn (string $s) => preg_replace('/[^a-z0-9]+/', '-', $s))
    |> (fn (string $s) => trim($s, '-'));

Rantai ini terbaca seperti daftar langkah, dan menambah langkah baru cukup satu baris. Tidak ada variabel sementara seperti $step1 atau $step2.

clone() Kini Fungsi dan Bisa Mengganti Properti Readonly

Perubahan kedua yang cukup besar: clone berhenti menjadi kata kunci murni dan sekarang bisa dipanggil seperti fungsi dengan parameter kedua berupa array properti. Signature-nya di php-src cabang 8.5 tertulis function clone(object $object, array $withProperties = []): object.

Kegunaan utamanya adalah membangun objek bergaya immutable tanpa memaksa semua properti masuk ke constructor. Pola wither yang biasanya ditulis panjang bisa dipersingkat:

<?php
final readonly class Response
{
    public function __construct(
        public int $statusCode,
        public string $reasonPhrase = '',
    ) {}

    public function withStatus(int $code, string $reason = ''): self
    {
        return clone($this, [
            'statusCode' => $code,
            'reasonPhrase' => $reason,
        ]);
    }
}

Properti readonly ikut bisa diganti pada proses kloning ini, selama penggantian dilakukan dari dalam kelas yang sesuai aturan visibility. Bentuk lama clone $x tetap sah. Nama properti yang tidak ada di objek akan memicu error, jadi array-nya harus persis.

#[\\NoDiscard]: Menandai Nilai Balik yang Penting

Bug tersulit dilacak biasanya bukan error, melainkan hasil fungsi yang lupa dipakai. PHP 8.5 memberi cara mendeklarasikannya lewat atribut #[\\NoDiscard]:

<?php
#[\\NoDiscard]
function normalize_email(string $email): string
{
    return strtolower(trim($email));
}

normalize_email('Anto@Example.com');           // muncul warning
$bersih = normalize_email('anto@example.com'); // aman, dipakai
(void) normalize_email('anto@example.com');    // sengaja dibuang

Cast (void) tidak mengubah jalannya program sama sekali. Fungsinya murni menyatakan niat: “gue tahu nilainya tidak dipakai, dan itu memang disengaja”. Static analyzer seperti PHPStan juga bisa memanfaatkan penanda yang sama.

Closure dan Cast di Constant Expression

Constant expression di PHP kini boleh berisi closure dan first-class callable. Menurut halaman migrasi resmi, dukungan itu berlaku untuk parameter atribut, nilai default properti maupun parameter, serta konstanta dan class constant. Efek praktisnya, dependency sederhana tidak lagi butuh method tambahan — nilai default parameter bisa langsung berupa arrow function, misalnya callable $cmp = fn ($a, $b) => $a['id'] <=> $b['id'] pada sebuah fungsi pengurutan.

Selain closure, cast juga diterima di constant expression. const BATAS = (int) 0.3; sekarang valid dan bernilai 0, padahal di versi sebelumnya menghasilkan fatal error. Ada juga dukungan atribut pada konstanta non-class, termasuk #[Deprecated] — berguna saat memensiunkan API internal bertahap.

array_first(), array_last(), dan Perbaikan Lain di Produksi

Dua fungsi baru di ekstensi Standard yang sepele tapi sering dipakai: array_first() mengembalikan nilai pertama sebuah array, array_last() mengembalikan nilai terakhir, dan keduanya memberi null kalau array kosong. Dibanding reset() dan end(), fungsi ini tidak menggeser internal pointer array, jadi lebih aman dipakai di tengah iterasi.

Cara Mencoba Tanpa Mengganggu Server

Kalau belum mau menyentuh server produksi, image resmi Docker sudah menyediakan PHP 8.5 lewat tag 8.5-cli. Satu perintah cukup untuk memastikan versinya: docker run --rm php:8.5-cli php -v. Mount folder kerja kalau ingin menjalankan file uji, misalnya docker run --rm -v "$PWD":/app -w /app php:8.5-cli php contoh-pipe.php.

Kalau kamu memakai Composer, jangan lupa menaikkan config.platform.php ke 8.5.0 supaya dependency yang di-resolve memang kompatibel. Untuk server sendiri, panduan install LAMP di Linux bisa jadi titik awal, tinggal ganti sumber paket PHP ke PPA atau repository distro yang sudah menyediakan 8.5. Kalau baru mulai belajar struktur kode PHP, artikel apa itu framework memberi konteksnya.

FAQ

Apakah pipe operator bisa dipakai di PHP 8.4?

Tidak. Operator |> baru ada di PHP 8.5, dan di versi lama akan langsung gagal saat file di-parse. Kalau project harus jalan di dua versi, tahan dulu pemakaian pipe atau uji keduanya lewat pipeline CI.

Apakah kode lama wajib diubah setelah upgrade ke 8.5?

Tidak wajib. Semua fitur di artikel ini aditif. Yang perlu dibaca justru daftar deprecated dan backward incompatible changes di dokumentasi migrasi.

Bisakah clone() mengganti properti private dari luar kelas?

Tidak. Parameter $withProperties tetap menghormati aturan visibility, jadi dari luar kelas hanya properti publik yang bisa diganti. Untuk properti private, lakukan penggantian di dalam method kelas itu sendiri.

Kesimpulan

PHP 8.5 bukan rilis yang mengubah segalanya, tapi ia memperbaiki tiga hal yang lama terasa canggung: menyusun fungsi berantai, mengkloning objek readonly, dan menandai nilai balik yang tidak boleh dibuang. Pipe operator paling layak dicoba lebih dulu karena dampaknya paling cepat terasa. Setelah itu, clone() dengan $withProperties sangat membantu kalau kamu memakai value object. Sisanya — array_first(), backtrace fatal error, ekstensi URI — bisa dipakai bertahap tanpa perlu refactor besar.

Referensi

Exit mobile version