strict_types

Mendeklarasikan mode strict dan alasan kode modern mengaktifkannya.

Daftar isi

Secara default, PHP mengonversi tipe argumen saat sebuah fungsi dipanggil dengan tipe yang tidak persis sama. Topik ini membahas deklarasi declare(strict_types=1) yang menonaktifkan konversi otomatis tersebut, perilaku pesan TypeError yang muncul akibatnya, aturan lingkup berlakunya, serta alasan kode modern mengaktifkan mode strict pada hampir setiap berkasnya.

Deklarasi mode strict#

Deklarasi declare(strict_types=1) ditulis pada baris-baris awal berkas dan mengubah cara PHP memperlakukan argumen fungsi di berkas tersebut. Tanpa deklarasi ini, PHP berada dalam mode lemah (coercive mode), yaitu argumen yang bertipenya hampir sesuai dikonversi tanpa peringatan apa pun. Dengan deklarasi ini, argumen harus bertipe persis seperti yang dinyatakan, dan pemanggilan dengan tipe lain melempar TypeError.

Deklarasi ini juga berlaku untuk fungsi bawaan PHP. Fungsi strlen menuntut parameter bertipe string, dan contoh berikut memanggilnya dengan bilangan bulat pada mode strict.

php
<?php

declare(strict_types=1);

try {
    var_dump(strlen("halo"));
    strlen(123);
} catch (TypeError $e) {
    echo $e->getMessage() . PHP_EOL;
}
text Keluaran
int(4)
strlen(): Argument #1 ($string) must be of type string, int given

Pemanggilan pertama berhasil karena "halo" memang bertipe string, sedangkan pemanggilan kedua dengan bilangan 123 langsung dihentikan. Kode try dan catch menangkap TypeError agar program tidak berhenti sepenuhnya, dan pesan errornya dicetak untuk diperiksa.

Membaca pesan TypeError#

Pesan TypeError tersusun dari empat bagian yang semuanya menjelaskan lokasi masalah. Nama fungsi muncul paling awal, diikuti nomor urut argumen beserta namanya, tipe yang diharapkan, dan tipe yang diberikan. Pada contoh sebelumnya, pesan strlen(): Argument #1 ($string) must be of type string, int given menyatakan bahwa argumen pertama bernama $string menuntut tipe string, tetapi menerima int.

Bagian-bagian ini membuat pesan TypeError dapat dibaca tanpa membuka kode fungsi terlebih dahulu. Untuk fungsi buatan sendiri, format pesannya sama, hanya saja PHP menambahkan lokasi baris pemanggilan pada bagian akhir pesan. Kebiasaan membaca pesan error secara lengkap menghemat waktu pencarian penyebab, karena nomor argumen dan kedua tipe yang disebutkan hampir selalu menunjuk baris yang perlu diperbaiki.

Mode strict berlaku pada berkas pemanggil#

Mode strict bersifat per berkas, dan berlakunya ditentukan oleh berkas tempat pemanggilan ditulis, bukan berkas tempat fungsi didefinisikan. Aturan ini sering mengejutkan pemula, sehingga contoh berikut dibagi menjadi dua berkas. Berkas pertama mendefinisikan fungsi bertipe tanpa deklarasi strict apa pun.

php fungsi-tipe.php
<?php

function kuadratkan(int $angka): int
{
    return $angka * $angka;
}

Berkas kedua mendeklarasikan mode strict, lalu memuat fungsi di atas melalui require dan memanggilnya dua kali. Perintah require mengambil berkas dari folder yang sama, sehingga program dijalankan dari folder tempat kedua berkas disimpan.

php pemanggil.php
<?php

declare(strict_types=1);

require 'fungsi-tipe.php';

echo kuadratkan(6) . PHP_EOL;

try {
    echo kuadratkan("7") . PHP_EOL;
} catch (TypeError $e) {
    echo "Pesan: " . strstr($e->getMessage(), ", called in", true) . PHP_EOL;
}
text Keluaran
36
Pesan: kuadratkan(): Argument #1 ($angka) must be of type int, string given

Pemanggilan dengan argumen string "7" gagal meskipun berkas fungsi tidak mendeklarasikan mode strict. Penentuannya ada pada berkas pemanggil.php, karena pemanggilan ditulis pada berkas tersebut. Versi lengkap pesan error diakhiri lokasi pemanggilan berupa nama berkas dan baris, dan fungsi strstr dengan argumen true memotong bagian lokasi tersebut agar keluaran tetap pendek.

Mengapa kode modern mengaktifkan strict_types#

Mode strict memindahkan deteksi kesalahan tipe ke titik terdekat dengan penyebabnya. Pada mode lemah, argumen dengan tipe yang salah diproses sampai jauh di dalam program, dan keanehan baru muncul pada keluaran atau data. Pada mode strict, program berhenti tepat di baris pemanggilan yang salah, sehingga perbaikan selesai lebih cepat dan jejak errornya tidak menyebar.

Mode strict juga melindungi nilai dari kerusakan yang tidak terlihat. Konversi otomatis dapat mengubah "1e2" menjadi 100 atau memotong pecahan menjadi bilangan bulat, dan kedua perubahan itu terjadi tanpa peringatan apa pun pada mode lemah. Dengan mode strict, nilai yang tidak persis sesuai ditolak, dan konversi yang memang diinginkan ditulis secara eksplisit dengan cast seperti (int) atau (string).

Kebiasaan ini berkembang bersama deklarasi tipe pada fungsi modern. Banyak pustaka dan framework modern mendeklarasikan tipe pada setiap parameter dan kembalian fungsi publiknya, dan mode strict membuat kontrak tipe itu ditegakkan di titik pemanggilan. Karena deklarasinya per berkas, penerapannya bisa bertahap, yaitu berkas baru diaktifkan lebih dahulu sedangkan berkas lama tetap berjalan dalam mode lemah.

Kesalahan umum#

Tiga kesalahan berikut paling sering ditemui saat mode strict diaktifkan.

  • Deklarasi declare(strict_types=1) ditempatkan setelah pernyataan lain, sehingga PHP menolak berkasnya. Perbaikannya adalah menempatkannya tepat setelah tag <?php, dan komentar boleh berada di atasnya.
  • Fungsi dipanggil dengan tipe yang perlu dikonversi, misalnya string "4" untuk parameter int, lalu program berhenti dengan TypeError. Perbaikannya adalah mengonversi secara eksplisit pada titik pemanggilan agar maksudnya terbaca.
  • Deklarasi strict diasumsikan berlaku untuk seluruh program karena satu berkas sudah mendeklarasikannya. Asumsi ini keliru karena berlakunya per berkas pemanggil. Perbaikannya adalah mendeklarasikannya pada setiap berkas baru sejak awal.
php Contoh: urutan deklarasi yang ditolak PHP
// tidak-dijalankan
$mode = "ketat";             // pernyataan lain menyusul lebih dulu
declare(strict_types=1);     // PHP menolak berkas ini saat dieksekusi

Ringkasan#

  • declare(strict_types=1) menonaktifkan konversi argumen otomatis pada berkasnya dan wajib menjadi pernyataan pertama setelah tag <?php.
  • Pemanggilan dengan tipe yang tidak sesuai melempar TypeError, baik pada fungsi bawaan maupun fungsi buatan sendiri, dan pesannya menyebut nomor argumen, tipe yang diharapkan, serta tipe yang diberikan.
  • Mode strict berlaku menurut berkas tempat pemanggilan ditulis, sehingga deklarasi pada satu berkas tidak menyebar ke berkas lain melalui include atau require.
  • Kode modern mengaktifkan mode strict karena kesalahan tipe terdeteksi di titik pemanggilan dan konversi yang diinginkan ditulis secara eksplisit.

Referensi#