Properti kelas yang diketik telah ditambahkan dalam PHP 7. 4 dan memberikan peningkatan besar pada sistem tipe PHP. Perubahan ini sepenuhnya ikut serta dan tidak merusak versi sebelumnya
Dalam posting ini kita akan melihat fitur secara mendalam, tapi pertama mari kita mulai dengan meringkas poin yang paling penting
- Mereka tersedia mulai dari PHP 7. 4, yang dijadwalkan akan dirilis pada November 2019
- Mereka hanya tersedia di kelas dan memerlukan pengubah akses. class Foo { public int $bar; } $foo = new Foo;7, class Foo { public int $bar; } $foo = new Foo;8 atau class Foo { public int $bar; } $foo = new Foo;9;
- Semua jenis diperbolehkan, kecuali var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization1 dan var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization2
Beginilah penampilan mereka saat beraksi
class Foo { public int $a; public ?string $b = 'foo'; private Foo $prop; protected static string $static = 'default'; }_Jika Anda tidak yakin tentang manfaat tambahan dari tipe, saya sarankan Anda membaca posting ini terlebih dahulu
Tidak diinisialisasi
Sebelum melihat hal-hal menyenangkan, ada aspek penting tentang properti yang diketik yang penting untuk dibicarakan terlebih dahulu
Terlepas dari apa yang mungkin Anda pikirkan pada pandangan pertama, kode berikut ini valid
class Foo { public int $bar; } $foo = new Foo;Meskipun nilai var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization3 bukan bilangan bulat setelah membuat objek var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization4, PHP hanya akan menampilkan kesalahan saat var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization3 diakses
var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initializationSeperti yang dapat Anda baca dari pesan kesalahan, ada "status variabel" jenis baru. tidak diinisialisasi
Jika var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization_3 tidak memiliki tipe, nilainya hanya var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization7. Jenis dapat dibatalkan, jadi tidak mungkin untuk menentukan apakah properti nullable yang diketik telah ditetapkan, atau hanya dilupakan. Itu sebabnya "tidak diinisialisasi" ditambahkan
Ada empat hal penting yang perlu diingat tentang uninitialized
- Anda tidak dapat membaca dari properti yang tidak diinisialisasi, hal itu akan mengakibatkan kesalahan fatal
- Karena status yang tidak diinisialisasi dicentang saat mengakses properti, Anda dapat membuat objek dengan properti yang tidak diinisialisasi, meskipun jenisnya tidak dapat dibatalkan
- Anda dapat menulis ke properti yang tidak diinisialisasi sebelum membacanya
- Menggunakan var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization_8 pada properti yang diketik akan membuatnya tidak diinisialisasi, sedangkan menghapus properti yang tidak diketik akan membuatnya var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization7
Terutama perhatikan bahwa kode berikut, di mana properti yang tidak diinisialisasi dan tidak dapat dibatalkan ditetapkan setelah membuat objek, valid
class Foo { public int $a; } $foo = new Foo; $foo->a = 1;Sementara status yang tidak diinisialisasi hanya diperiksa saat membaca nilai properti, validasi tipe dilakukan saat menulisnya. Ini berarti Anda dapat yakin bahwa tidak ada tipe yang tidak valid yang akan berakhir sebagai nilai properti
Apa yang baru di PHP 8. 2
Default dan konstruktor
Mari kita lihat lebih dekat bagaimana nilai yang diketik dapat diinisialisasi. Dalam kasus tipe skalar, dimungkinkan untuk memberikan nilai default
class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }Perhatikan bahwa Anda hanya dapat menggunakan var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization_7 sebagai default jika jenisnya benar-benar dapat dibatalkan. Ini mungkin tampak jelas, tetapi ada beberapa perilaku lama dengan default parameter yang mengizinkan hal berikut
function passNull(int $i = null) { /* … */ } passNull(null);Untungnya perilaku membingungkan ini tidak diperbolehkan dengan properti yang diketik
Perhatikan juga bahwa tidak mungkin memiliki nilai default dengan class Foo { public int $a; } $foo = new Foo; $foo->a = 1;1 atau tipe kelas. Anda harus menggunakan konstruktor untuk menyetel defaultnya
Tempat yang jelas untuk menginisialisasi nilai yang diketik tentu saja adalah konstruktor
class Foo { private int $a; public function __construct(int $a) { $this->a = $a; } }Tapi juga ingat apa yang saya sebutkan sebelumnya. sah untuk menulis ke properti yang tidak diinisialisasi, di luar konstruktor. Selama tidak ada yang membaca dari properti, pemeriksaan yang tidak diinisialisasi tidak dilakukan
Jenis jenis
Jadi apa sebenarnya yang bisa diketik dan bagaimana caranya?
Berdasarkan jenis yang tersedia, hampir semua jenis dapat digunakan, kecuali var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization1 dan var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization2
Karena var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization_1 berarti tidak adanya nilai, masuk akal bahwa itu tidak dapat digunakan untuk mengetikkan nilai. var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization2 namun sedikit lebih bernuansa
Lihat, "callable" di PHP bisa ditulis seperti itu
$callable = [$this, 'method'];Katakanlah Anda memiliki kode (rusak) berikut
class Foo { public callable $callable; public function __construct(callable $callable) { /* … */ } } class Bar { public Foo $foo; public function __construct() { $this->foo = new Foo([$this, 'method']) } private function method() { /* … */ } } $bar = new Bar; ($bar->foo->callable)();Dalam contoh ini, class Foo { public int $a; } $foo = new Foo; $foo->a = 1;_7 mengacu pada class Foo { public int $a; } $foo = new Foo; $foo->a = 1;8 pribadi, tetapi disebut dalam konteks var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization4. Karena masalah ini, diputuskan untuk tidak menambahkan dukungan var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization2
Ini bukan masalah besar, karena class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }_1 adalah tipe yang valid, yang akan mengingat konteks class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }2 di mana itu dibangun
Dengan itu, berikut adalah daftar semua jenis yang tersedia
- bool
- int
- mengambang
- rangkaian
- Himpunan
- dapat diubah
- obyek
- ?
- diri dan orang tua
- Kelas & antarmuka
Jenis pemaksaan dan ketat
PHP, sebagai bahasa dinamis yang kita sukai dan benci, akan mencoba memaksa atau mengonversi tipe jika memungkinkan. Katakanlah Anda melewatkan string di mana Anda mengharapkan bilangan bulat, PHP akan mencoba dan mengonversi string itu secara otomatis
function coerce(int $i) { /* … */ } coerce('1'); // 1Prinsip yang sama berlaku untuk properti yang diketik. Kode berikut ini valid dan akan mengonversi class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }3 menjadi class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }4
class Foo { public int $bar; } $foo = new Foo;0Jika Anda tidak menyukai perilaku ini, Anda dapat menonaktifkannya dengan mendeklarasikan tipe yang ketat
Jenis varians dan pewarisan
Meskipun PHP7. 4 diperkenalkan , properti yang diketik masih invarian. Ini berarti bahwa yang berikut ini tidak valid
class Foo { public int $bar; } $foo = new Foo;_2Jika contoh di atas tampaknya tidak signifikan, Anda harus melihat yang berikut ini
class Foo { public int $bar; } $foo = new Foo;_3PHP akan mengganti class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }_5 di belakang layar dengan kelas konkret yang dirujuknya, sebelum menjalankan kode. Ini berarti bahwa kesalahan yang sama akan dilemparkan dalam contoh ini. Satu-satunya cara untuk mengatasinya, adalah dengan melakukan hal berikut
class Foo { public int $bar; } $foo = new Foo;_4Berbicara tentang pewarisan, Anda mungkin kesulitan menemukan kasus penggunaan yang baik untuk menimpa jenis properti yang diwariskan
Meskipun saya setuju dengan sentimen itu, perlu dicatat bahwa adalah mungkin untuk mengubah jenis properti yang diwariskan, tetapi hanya jika pengubah akses juga berubah dari class Foo { public int $bar; } $foo = new Foo;9 menjadi class Foo { public int $bar; } $foo = new Foo;8 atau class Foo { public int $bar; } $foo = new Foo;7
Kode berikut ini valid
class Foo { public int $bar; } $foo = new Foo;5Namun, mengubah jenis dari nullable menjadi non-nullable atau sebaliknya, tidak diperbolehkan
class Foo { public int $bar; } $foo = new Foo;_6Melihat tpyo? . Jika Anda ingin tetap mendapatkan informasi terbaru tentang apa yang terjadi di blog ini, Anda dapat mengikuti saya di Twitter atau berlangganan buletin saya. Email Berlangganan
Masih ada lagi
Seperti yang dikatakan di awal posting ini, properti yang diketik adalah tambahan utama untuk PHP. Masih banyak lagi yang bisa dikatakan tentang mereka. Saya sarankan Anda membaca RFC untuk mengetahui semua detail kecil yang rapi
Jika Anda baru menggunakan PHP 7. 4, Anda mungkin ingin membaca daftar lengkap perubahan yang dibuat dan fitur yang ditambahkan. Sejujurnya, ini adalah salah satu rilis terbaik dalam waktu yang lama, dan sepadan dengan waktu Anda
Terakhir, jika Anda memiliki pemikiran yang ingin Anda bagikan tentang topik ini, saya ingin mendengar pendapat Anda. Anda dapat menghubungi saya melalui Twitter atau email