Tidak semua fungsi dipanggil demi nilainya: sebagian bernilai justru karena efek sampingnya — mencetak laporan, menyimpan data, atau menghentikan program saat keadaan darurat. Untuk dua makna “tidak” tersebut PHP menyediakan dua return type khusus. void menyatakan “fungsi selesai secara normal tetapi tidak menyerahkan nilai”, sedangkan never — hadir sejak PHP 8.1 — menyatakan “fungsi tidak pernah mengembalikan kontrol ke pemanggilnya” karena selalu melempar error atau menghentikan program. Pada Chapter ini kita membedah keduanya satu per satu, melihat bagaimana PHP menolak pelanggarannya, lalu menutup dengan peran never di mata alat analisis statis.
void untuk Fungsi Tanpa Nilai Balik #
Deklarasi : void menegaskan bahwa pemanggil tidak akan menerima nilai yang berguna. Fungsi seperti ini biasanya disebut prosedur: ia melakukan sesuatu, lalu selesai:
<?php
function sapaPengguna(string $nama): void
{
echo "Halo, $nama!\n";
}
sapaPengguna("Budi");Output yang Dihasilkan:
Halo, Budi!Fungsi sapaPengguna() hanya mencetak sapaan lalu berakhir — tidak ada return sama sekali, dan itulah bentuk paling alami dari fungsi void. Pemanggil tidak diminta menampung hasilnya, dan mencoba menggunakannya dalam ekspresi hanya memberikan null. Sebelum melihat itu, mari pelajari satu alat penting lainnya: keluar dari fungsi void lebih awal dengan return; tanpa nilai:
<?php
function catatAktivitas(string $pesan): void
{
if ($pesan === "") {
return; // keluar dari fungsi lebih awal, tanpa nilai
}
echo "[log] $pesan\n";
}
catatAktivitas("Pengguna login");
catatAktivitas("");
echo "Selesai\n";Output yang Dihasilkan:
[log] Pengguna login
SelesaiPemanggilan kedua membawa string kosong, sehingga catatAktivitas() keluar lewat return; lebih awal sebelum sempat mencatat apa pun. Pernyataan return; tanpa nilai memang sah untuk fungsi void — ia hanya mengakhiri jalannya fungsi, bukan menyerahkan nilai. Itulah sebabnya baris Selesai tetap tercetak: fungsi yang kembali lebih awal tidak menghentikan program, hanya dirinya sendiri.
Lalu apa yang diterima pemanggil bila hasil fungsi void dipakai dalam ekspresi? Jawabannya null:
<?php
function resetHitungan(): void
{
// tidak ada pernyataan return sama sekali
}
$hasil = resetHitungan();
var_dump($hasil);Output yang Dihasilkan:
NULLNilai $hasil adalah null — bukan error, bukan peringatan. PHP memperlakukan absennya nilai sebagai null, tetapi menandai niat tersebut lewat deklarasi void agar pembaca kode tahu bahwa null ini memang tidak dimaksudkan untuk dipakai. Menampung hasil fungsi void ke variabel hampir selalu pertanda kekeliruan desain; deklarasi void hadir justru agar kebiasaan semacam itu mudah terlihat.
Pelanggaran void Ditolak Sebelum Program Berjalan #
PHP menolak fungsi void yang mencoba mengembalikan nilai — dan penolakannya terjadi sebelum satu baris pun dieksekusi. Simpan berikut sebagai poin.php lalu jalankan:
<?php
function hitungPoin(): void
{
return 42;
}
echo "sebelum pemanggilan\n";Output yang Dihasilkan:
Fatal error: A void function must not return a value in /home/z/my-project/php-course/content/php/tipe-data-dan-type-system/never-dan-void/.verify_tmp.php on line 4Perhatikan bahwa kalimat sebelum pemanggilan tidak pernah tercetak, padahal barisnya berada setelah definisi fungsi dan fungsi tersebut tidak pernah dipanggil. Pemeriksaan ini terjadi pada tahap penerjemahan: begitu PHP selesai membaca berkas, ia sudah tahu bahwa hitungPoin() berbohong tentang kekosongannya dan menolak seluruh berkas. Pesan A void function must not return a value juga menunjuk baris 4 — baris pernyataan return 42; yang melanggar. Nama berkas .verify_tmp.php pada pesan adalah berkas sementara milik alat verifikasi buku ini, sama seperti pada Chapter sebelumnya; berkas simpanan Anda sendiri akan tertulis dengan nama dan lokasinya.
never untuk Fungsi yang Tidak Pernah Kembali #
Bayangkan fungsi pembantu yang tugasnya tunggal: gagal. Ia dipanggil ketika kondisi mustahil terjadi, dan satu-satunya pekerjaannya adalah melempar error dengan pesan yang rapi. Fungsi seperti ini tidak sekadar “tidak mengembalikan nilai” — ia tidak pernah sampai pada titik kembali sama sekali. Untuk itulah PHP 8.1 memperkenalkan never:
<?php
function gagalKoneksi(string $alasan): never
{
throw new RuntimeException("Koneksi gagal: $alasan");
}
try {
gagalKoneksi("database tidak merespons");
} catch (RuntimeException $e) {
echo "Tertangkap: ", $e->getMessage(), "\n";
}
echo "Program tetap berjalan\n";Output yang Dihasilkan:
Tertangkap: Koneksi gagal: database tidak merespons
Program tetap berjalanMari kita bedah alurnya. Pernyataan throw di dalam gagalKoneksi() melempar object RuntimeException — pernyataan itu menghentikan fungsi seketika dan tidak pernah kembali, persis janji never. Blok try/catch di pemanggil kemudian menangkap error tersebut sehingga program tidak mati: kalimat Tertangkap: ... tercetak dari blok catch, lalu eksekusi lanjut ke baris setelahnya. Mekanisme throw, try, dan catch ini akan kita bedah tuntas pada Section Error Handling
; untuk sekarang, cukup pahami bahwa catch adalah penangkap error yang dilempar.
Ada satu jalan lain untuk memenuhi never: menghentikan seluruh program dengan exit():
<?php
function hentikanProgram(string $alasan): never
{
echo "Program dihentikan: $alasan\n";
exit(0);
}
hentikanProgram("mode pemeliharaan aktif");
echo "Baris ini tidak pernah tercetak\n";Output yang Dihasilkan:
Program dihentikan: mode pemeliharaan aktifKeluaran hanya berisi satu kalimat karena exit(0) menghentikan keseluruhan skrip — bukan hanya fungsi hentikanProgram(), tetapi juga baris echo yang menyusulnya. Angka 0 pada exit(0) adalah status keluar yang dilaporkan ke sistem operasi; angka mana pun tetap memenuhi never karena yang penting adalah program berakhir di dalam fungsi tersebut. Pola seperti ini lazim pada utilitas CLI: setelah mencetak pesan penutup atau mengalihkan pengguna ke halaman lain, tidak ada alasan melanjutkan sisa skrip.
Pelanggaran never #
Janji never ikut ditagih. Bila fungsi never memiliki jalur yang jatuh ke akhir body tanpa melempar atau keluar, PHP membalasnya saat runtime. Simpan berikut sebagai bayar.php:
<?php
function prosesPembayaran(): never
{
echo "memproses pembayaran...\n";
// tidak ada throw, tidak ada exit
}
prosesPembayaran();Output yang Dihasilkan:
memproses pembayaran...
Fatal error: Uncaught TypeError: prosesPembayaran(): never-returning function must not implicitly return in /home/z/my-project/php-course/content/php/tipe-data-dan-type-system/never-dan-void/.verify_tmp.php:6
Stack trace:
#0 /home/z/my-project/php-course/content/php/tipe-data-dan-type-system/never-dan-void/.verify_tmp.php(8): prosesPembayaran()
#1 {main}
thrown in /home/z/my-project/php-course/content/php/tipe-data-dan-type-system/never-dan-void/.verify_tmp.php on line 6Berbeda dengan pelanggaran void, penolakan ini baru terjadi saat fungsi berjalan: kalimat memproses pembayaran... sempat tercetak, lalu TypeError muncul ketika eksekusi menyentuh akhir body — never-returning function must not implicitly return. Penolakan yang lebih dini berlaku untuk return; eksplisit: pesan A never-returning function must not return muncul sejak tahap penerjemahan, sama seperti kasus void. Terakhir, never dan void sama-sama tidak boleh dipakai sebagai tipe parameter — keduanya bermakna khusus untuk nilai kembali.
void atau never #
Perbedaan keduanya dapat dirangkum dalam satu tabel:
| Aspek | void | never |
|---|---|---|
| Janji kepada pemanggil | tidak ada nilai yang berguna | tidak akan pernah kembali |
| Cara mengakhiri | return; atau akhir body | throw atau exit |
| Hasil dalam ekspresi | null | tidak relevan — tak pernah sampai |
| Contoh penggunaan | prosedur: mencetak, menyimpan | helper pelempar error, penghenti program |
Aturan praktisnya sederhana. Gunakan void bila fungsi memang selesai secara normal; gunakan never hanya bila setiap jalur eksekusinya pasti melempar error atau keluar program. Bila ada satu jalur saja yang kembali — misalnya helper yang melempar error untuk input kosong tetapi mengembalikan nilai untuk input valid — maka never salah, dan tipe tersebut bukan milik fungsi itu.
never di Mata Analisis Statis #
Manfaat terbesar never justru terasa sebelum program berjalan. Ketika PHPStan atau Psalm melihat fungsi bertipe never, alat tersebut menyimpulkan bahwa semua kode setelah pemanggilan fungsi itu tidak akan pernah dieksekusi — dan menandai kode tersebut sebagai unreachable. Tanpa never, helper pelempar error tampak seperti fungsi biasa yang kembali dengan tenang, sehingga alat analisis justru melaporkan kode yang sah sebagai selalu dieksekusi, atau lebih buruk: melewatkan variabel yang tidak pernah diberi nilai.
Pola nyatanya mudah dijumpai di framework modern: helper yang mengalihkan halaman lalu menghentikan eksekusi, atau fungsi abort() yang melempar response error. Semuanya ditutup dengan never agar pembaca kode maupun mesin penganalisis sepakat bahwa baris berikutnya hanya berlaku bila helper tersebut tidak terpicu. Kita akan mempraktikkan analisis semacam ini pada Section Type System dan Static Analysis
.
Ringkasan #
void menyatakan fungsi yang selesai tanpa menyerahkan nilai — return; diperbolehkan, hasil dalam ekspresi bernilai null, dan pelanggaran return bernilai ditolak sebelum program berjalan. never menyatakan fungsi yang tidak pernah kembali — wajib berakhir lewat throw atau exit, pelanggarannya ditagih runtime, dan keberadaannya membantu alat analisis statis mengenali kode yang tidak terjangkau. Dua tipe ini menutup katalog return type PHP; tinggal satu keterampilan yang belum kita asah di Section ini: membaca pesan TypeError yang berulang kali muncul — tuntas di Chapter berikutnya.