Sampai titik ini kita menulis fungsi sederhana dan PHP memperlakukannya dengan santai: bila tipe argumen tidak persis cocok, PHP diam-diam mengonversinya. Kelonggaran ini nyaman, tetapi juga berbahaya — string "100000" yang lolos ke perhitungan nominal hari ini bisa berubah jadi string "100.000" berkoma dari locale lain besok, dan bug semacam itu sulit dilacak. PHP menyediakan declare(strict_types=1) untuk mematikan konversi otomatis tersebut. Pada Chapter ini kita membandingkan mode lemah dan mode ketat pada pemanggilan yang sama, memetakan aturan konversi mode lemah, lalu membahas posisi declare yang benar dan berkas mana yang sebenarnya menentukan mode.
Perilaku Mode Lemah (Default) #
Tanpa declare apa pun, PHP berjalan pada weak mode (mode lemah). Saat argumen tidak bertipe tepat, PHP berusaha mengonversinya terlebih dahulu, baru menyerah dengan TypeError bila konversi mustahil:
<?php
function hitungDiskon(int $harga, float $persen): float
{
return $harga * $persen;
}
// String numerik "100000" dipaksa menjadi int 100000.
var_dump(hitungDiskon("100000", 0.1));
// Float 6.0 dipaksa menjadi int 6 karena tidak kehilangan presisi.
var_dump(hitungDiskon(6.0, 0.5));
// Nilai balik int dipaksa menjadi string oleh deklarasi return string.
function ubahKeString(int $x): string
{
return $x;
}
var_dump(ubahKeString("25"));Output yang Dihasilkan:
float(10000)
float(3)
string(2) "25"Mari kita bedah ketiga pemanggilan di atas:
hitungDiskon("100000", 0.1): parameter pertama bertipeinttetapi menerima string"100000". Karena string tersebut numerik sempurna, PHP mengonversinya menjadi100000— hasil100000 * 0.1adalahfloat(10000).hitungDiskon(6.0, 0.5): float6.0dikonversi menjadi int6karena nilainya utuh — tidak ada angka pecahan yang dibuang.ubahKeString("25"): konversi terjadi dua kali — argumen"25"menjadi int25, lalu nilai balik int25dipaksa menjadistring(2) "25"oleh deklarasi return: string.
Aturan Koersi pada Mode Lemah #
Konversi mode lemah tidak acak; aturannya dapat dipetakan. Tabel berikut merangkum kasus yang paling sering dijumpai:
| Nilai yang datang | Parameter bertipe | Hasil |
|---|---|---|
"100000", "12 ", " 7" (string numerik) | int / float | dikonversi, spasi awal/akhir diabaikan |
"12.5" (string pecahan) | int | Deprecated, nilai dipotong menjadi 12 |
6.0 (float utuh) | int | dikonversi menjadi 6 |
6.9 (float pecahan) | int | Deprecated, nilai dipotong menjadi 6 |
"ajax", "" (string apa pun) | bool | mengikuti truthiness: true / false |
"murah" (string non-numerik) | int / float | TypeError, program berhenti |
null | tipe skalar non-nullable | TypeError — null tidak pernah dipaksa |
Dua baris terakhir tampak di tabel sebagai error, dan sisanya tampak damai — tetapi perhatikan bahwa dua baris Deprecated pun sebenarnya lencana kuning: konversi berjalan, namun PHP memperingatkan bahwa presisi hilang tanpa Anda perintahkan. Simpan contoh berikut sebagai koersi.php lalu jalankan:
<?php
function tambah(int $a, int $b): int
{
return $a + $b;
}
// Spasi di awal/akhir string numerik tetap diterima.
var_dump(tambah("12 ", 3));
var_dump(tambah(" 7", 3));
// String pecahan yang dipotong memicu Deprecated, bukan TypeError.
var_dump(tambah("12.5", 3));
function simpan(bool $konfirmasi): string
{
return $konfirmasi ? "disimpan" : "dibatalkan";
}
// Koersi ke bool mengikuti aturan truthiness string.
var_dump(simpan("ajax"));
var_dump(simpan(""));Output yang Dihasilkan:
int(15)
int(10)
Deprecated: Implicit conversion from float-string "12.5" to int loses precision in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php on line 2
int(15)
string(8) "disimpan"
string(10) "dibatalkan"Empat nilai pertama menunjukkan string numerik diterima dalam berbagai bentuk: "12 " dan " 7" dibersihkan spasinya, sedangkan "12.5" dipotong menjadi 12 dengan peringatan Deprecated — perhatikan bahwa peringatan tersebut merujuk ke baris deklarasi fungsi tambah(). Dua nilai terakhir memperlihatkan koersi ke bool: string non-kosong selain "0" bernilai true, sehingga "ajax" berarti setuju dan "" berarti batal. Aturan truthiness string ini dibahas tuntas pada Chapter Booleans
nanti.
Mengaktifkan Mode Ketat #
Mode ketat dinyalakan lewat declare(strict_types=1) di baris paling atas berkas. Setelah aktif, PHP berhenti mengonversi argumen dan nilai balik — tipe harus tepat:
<?php
declare(strict_types=1);
function hitungDiskon(int $harga, float $persen): float
{
return $harga * $persen;
}
// Argumen dengan tipe yang tepat diterima seperti biasa.
var_dump(hitungDiskon(100000, 0.1));
// Pengecualian: int tetap boleh melebar menjadi float.
function setengah(float $x): float
{
return $x / 2;
}
var_dump(setengah(7));Output yang Dihasilkan:
float(10000)
float(3.5)Pemanggilan pertama kini memakai argumen int asli, bukan string. Bagian kedua memperlihatkan satu-satunya kelonggaran yang tersisa: integer 7 tetap diterima parameter float karena setiap int selalu dapat diwakili float tanpa kehilangan nilai — pelebaran (widening) ini diizinkan bahkan di mode ketat. Bandingkan dengan pemanggilan string yang sama persis dengan contoh mode lemah di awal Chapter — simpan sebagai gagal.php:
<?php
declare(strict_types=1);
function hitungDiskon(int $harga, float $persen): float
{
return $harga * $persen;
}
var_dump(hitungDiskon("100000", 0.1));Output yang Dihasilkan:
Fatal error: Uncaught TypeError: hitungDiskon(): Argument #1 ($harga) must be of type int, string given, called in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php on line 9 and defined in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php:4
Stack trace:
#0 /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php(9): hitungDiskon('100000', 0.1)
#1 {main}
thrown in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php on line 4Pemanggilan yang tadinya berhasil kini menghentikan program dengan TypeError: parameter $harga meminta int, yang datang string. Deklarasi nilai balik juga dijaga dengan cara yang sama — simpan berikut sebagai label.php:
<?php
declare(strict_types=1);
function label(float $x): int
{
return $x;
}
var_dump(label(3.9));Output yang Dihasilkan:
Fatal error: Uncaught TypeError: label(): Return value must be of type int, float returned in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php:6
Stack trace:
#0 /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php(9): label(3.9)
#1 {main}
thrown in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php on line 6Kali ini TypeError melaporkan pelanggaran pada sisi nilai balik: fungsi label() berjanji mengembalikan int tetapi return $x; menyerahkan float. Pesan error bahkan menunjuk baris pernyataan return yang berbohong. Anatomi pesan seperti ini akan kita baca secara sistematis pada Chapter Memahami Type Errors
.
Posisi declare yang Benar #
declare(strict_types=1) wajib menjadi pernyataan (statement) pertama pada berkas — bukan sekadar baris pertama. Komentar boleh mendahuluinya karena komentar bukan pernyataan, tetapi kode apa pun sebelum declare langsung membatalkannya. Simpan berikut sebagai urutan.php:
<?php
$judul = "Laporan Penjualan";
declare(strict_types=1);Output yang Dihasilkan:
Fatal error: strict_types declaration must be the very first statement in the script in /home/z/my-project/php-course/content/php/sintaks-dasar-dan-variabel/strict-types/.verify_tmp.php on line 4PHP menolak berkas ini sejak tahap penerjemahan: variabel $judul sudah menjadi pernyataan pertama, sehingga declare kehilangan haknya. Kesalahan klasiknya adalah menyimpan declare setelah require atau setelah kode konfigurasi — pastikan baris tersebut selalu berada tepat di bawah <?php (dan komentar bila perlu).
Siapa yang Menentukan Mode: Berkas Pemanggil #
Kami menguji kedua arah aturan ini pada PHP 8.4: berkas pustaka tanpa declare yang dipanggil dari berkas ber-strict_types menghasilkan TypeError untuk argumen string; berkas pustaka ber-strict_types yang dipanggil dari berkas biasa justru tetap menerima konversi. Konsekuensinya praktis: aktifkan strict_types di setiap berkas yang Anda tulis — termasuk berkas masuk (entry point) — karena mode tidak pernah menular antar berkas. Peran strict_types di dalam berkas pustaka dan proyek nyata dibahas lagi pada Chapter Strict Types dalam Fungsi
.
Ringkasan #
Mode lemah mengonversi argumen dan nilai balik mengikuti tabel koersi — string numerik diterima, float pecahan memicu Deprecated, dan nilai mustahil dikonversi berujung TypeError. Mode ketat mematikan seluruh konversi kecuali pelebaran int ke float, menuntut declare(strict_types=1) sebagai pernyataan pertama berkas, dan mengikuti lokasi pemanggilan. Dengan dua mode ini kita telah melihat mesin konversi dan penegakan tipe PHP bekerja — saatnya menarik mundur kamera dan memetakan seluruh type system PHP sebagai jembatan ke Section berikutnya.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
ketat.php
Unduh berkas<?php
declare(strict_types=1);
// ketat.php — mode strict types untuk Chapter Strict Types.
// Jalankan dengan: php ketat.php
function hitungDiskon(int $harga, float $persen): float {
return $harga * $persen;
}
// String numerik DITOLAK di mode strict — TypeError ditangkap agar program lanjut.
try {
var_dump(hitungDiskon("100000", 0.1));
} catch (TypeError $e) {
echo "TypeError ditangkap — argumen string tidak diterima\n";
}
// Argumen dengan tipe yang tepat diterima seperti biasa.
var_dump(hitungDiskon(100000, 0.1));
// Pengecualian: int tetap boleh dilebarkan menjadi float di mode strict.
function setengah(float $x): float {
return $x / 2;
}
var_dump(setengah(7));
lemah.php
Unduh berkas<?php
// lemah.php — mode weak coercion (bawaan PHP) untuk Chapter Strict Types.
// Jalankan dengan: php lemah.php
function hitungDiskon(int $harga, float $persen): float {
return $harga * $persen;
}
// String numerik "100000" dipaksa menjadi int 100000.
var_dump(hitungDiskon("100000", 0.1));
// Float 6.0 dipaksa menjadi int 6 (tanpa kehilangan presisi).
var_dump(hitungDiskon(6.0, 0.5));
// Nilai balik int dipaksa menjadi string oleh deklarasi return string.
function ubahKeString(int $x): string {
return $x;
}
var_dump(ubahKeString("25"));