Di PHP 8, kami menggunakan kelas, properti, dan konstanta kelas, metode, fungsi, parameter untuk mengakses atribut
Di PHP 8, Reflection API mengirimkan metode getAttribute() pada setiap objek Reflection yang cocok
Metode getAttribute() mengembalikan array ilustrasi ReflectionAttribute yang dapat diminta untuk nama atribut, argumen, dan untuk membuat instance dari atribut yang ditandai
Ini terdengar seperti pertanyaan wawancara yang sepele, kami tahu. Anda dapat dengan mudah menemukan metode yang terdokumentasi dengan baik dengan Refleksi. Beberapa guru sejati bahkan memberi kami cara non-Refleksi lainnya untuk melakukan hal yang sama. Namun, saat Anda mulai mengimplementasikannya sendiri, Anda dapat mengalami banyak masalah tak terduga dan aneh. Ini termasuk, tetapi tidak terbatas pada
Anda tidak dapat melakukannya dalam satu baris hanya dengan menggunakan RefleksiAnda harus bermain-main dengan objek API Refleksi, tetapi jangan berani-berani lupa menelepon setAccessible(true) terlebih dahulu
tangkapan layar asli dari solusi Stackoverflow. Harta pribadi orang tua tidak dihitung ¯\_(ツ)_/¯
Itu benar. jika Anda mencoba mengakses properti pribadi yang diwariskan dari kelas induk, potongan kode Stackoverflow yang disetujui akan gagal
Mengakses privat orang tua gagal di PHP
Saya yakin ada penjelasan akademis yang masuk akal untuk perilaku ini. Jika Anda tahu alasannya, silakan bagikan dengan kami di komentar. Mungkin sesuatu seperti
Properti pribadi kelas induk tidak dapat diakses selama runtime dari dalam kelas anak. Oleh karena itu, mereka juga tidak dapat diakses melalui Reflection API
Kita bisa melihat sedikit perbedaan pada pesan error PHP pada screenshot dari 3v4l. org. alih-alih “Properti p tidak ada” kita mendapatkan “Properti Anak. $p tidak ada”. Ini menyiratkan bahwa properti kelas induk bahkan tidak dilihat
Jika Anda memikirkannya, Anda tidak dapat mengakses properti pribadi orang tua Anda sebagai seorang anak, jadi itu masuk akal
Terlepas dari semua lelucon, bagaimana kita bisa membaca properti pribadi suatu objek di PHP? . php-refleksi. Mari kita lihat sebuah contoh
PHP 7. 4 akhirnya membawa properti yang diketik. Ini adalah fitur yang saya nantikan, dan saya telah menghabiskan waktu berkualitas mengerjakan proyek saya yang sudah ada untuk menambahkan dukungan untuk properti yang diketik
Dengan properti yang diketik, Anda dapat mengatur tipe untuk semua properti kelas. Saat tipe disetel, mesin PHP mencegah siapa pun menyetel tipe yang berbeda ke properti kelas
class Example { public string $name; public DateTime $birthday; }Cuplikan di atas akan memastikan bahwa properti class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_7 akan selalu menjadi objek class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true8. Sebelum PHP7. 4, pola data ketat semacam ini harus memiliki class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true9 dan class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);0 metode untuk menegakkan integritas data
Jenis properti yang didukung
Jenis yang didukung untuk properti kelas- Jenis skalar. class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);1, class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);2, class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);3, dan class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);4
- Jenis senyawa. class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);5, class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);6 dan class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);7
- Nama kelas atau antarmuka apa pun (seperti class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_8, class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);9) dan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...0
- Referensi ke objek induk dan objek sendiri. Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...1 dan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...2
- Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ..._3. Memiliki properti Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ..._3 tidak masuk akal
- Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ..._5. Tidak didukung karena perilakunya tidak dapat diprediksi. Lihatlah RFC callables yang konsisten untuk latar belakang lebih lanjut. Ini pada dasarnya menjadi merepotkan ketika callable dapat dideklarasikan dengan sintaks array, mis. g. sebagai Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ..._6
Di sinilah sebagian besar penarikan rambut mungkin terjadi. Dengan PHP7. 4 properti yang diketik, properti kelas memiliki status yang tidak diinisialisasi. Ini berarti bahwa properti belum diinisialisasi. Ini tidak sama dengan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ..._8
Jika tidak ada tipe yang dideklarasikan, properti memiliki Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8 sebagai nilai yang tidak diinisialisasi
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_Saat sebuah tipe dideklarasikan, semua properti akan memiliki status yang tidak diinisialisasi. Tidak diperbolehkan mengakses properti kelas sebelum menetapkan nilai eksplisit
class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);_Dalam cuplikan ini, properti class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid_0 tidak diinisialisasi. Ini tidak sama dengan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ..._8, dan cuplikan di atas akan menimbulkan kesalahan
Periksa status yang tidak diinisialisasi
Anda dapat memeriksa apakah properti kelas tidak diinisialisasi menggunakan class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid2. Karena nilai ini tidak sama dengan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8, Anda tidak dapat menggunakan class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid4 untuk memeriksa apakah properti tidak diinisialisasi
Setel ulang properti ke status tidak diinisialisasi
Untuk mengatur ulang properti kembali ke keadaan tidak diinisialisasi, gunakan class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid5. Setelah tidak disetel, mencoba mengakses properti tanpa menetapkan nilainya akan menimbulkan kesalahan class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid6 yang sama
Jenis yang dapat dibatalkan
Mirip dengan PHP7. 1's nullable type, tipe properti juga dapat ditandai nullable. Untuk menandai properti bisa menjadi nol, awali jenisnya dengan tanda tanya, mis. g. class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid_7
class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // ValidBahkan jika sebuah properti ditandai nullable, nilainya yang tidak diinisialisasi tidak akan menjadi Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8. Misalnya, cuplikan di bawah ini masih akan menimbulkan kesalahan
class Example { public ?string $name; } $foo = new Example(); var_dump($foo->name); // Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initializationMeskipun ini tampak rumit untuk dikerjakan, ini memberikan fitur brilian yang dapat Anda yakini bahwa properti kelas akan selalu bertipe seperti itu. Jika nilainya tidak diinisialisasi, PHP akan menyerah dan memunculkan kesalahan alih-alih mengembalikan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8, seperti untuk properti yang tidak diketik
Jenis yang ketat
Properti kelas juga mendukung deklarasi tipe ketat dengan class Example { public ?string $name; } $foo = new Example(); var_dump($foo->name); // Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization0 di bagian atas blok file PHP. Tanpa tipe yang ketat, PHP akan memasukkan nilai ke tipe properti
class Example { public string $name; } $foo = new Example(); $foo->name = 420; var_dump($foo->name); // string(3) "420"Perhatikan bagaimana kami menyetel class Example { public ?string $name; } $foo = new Example(); var_dump($foo->name); // Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization_1 ke properti class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);2, dan panggilan class Example { public ?string $name; } $foo = new Example(); var_dump($foo->name); // Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization3 mengembalikan class Example { public ?string $name; } $foo = new Example(); var_dump($foo->name); // Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization4 sebagai class Example { public string $name; } $foo = new Example(); var_dump($foo->name === null);2. Saat menetapkan nilai, mesin memberikan nilai ke tipe yang dideklarasikan
Untuk meminimalkan masalah dengan tipe juggling dan untuk memanfaatkan sepenuhnya properti yang diketik, saya sarankan Anda menguji kelas Anda dengan class Example { public ?string $name; } $foo = new Example(); var_dump($foo->name); // Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization0. Sangat mudah untuk mengabaikan ketika PHP sedang membantu ketika dilemparkan ke tipe untuk Anda, tetapi ini bisa menjadi akar dari beberapa bug di hilir. Lebih mudah untuk men-debug kesalahan yang muncul segera daripada bug yang hanya terjadi pada Jumat malam pukul 6. 28PM, hanya saat DST aktif
Properti statis dan referensi
Properti statis juga dapat memiliki tipe yang dideklarasikan. Ini mungkin tampak seperti detail yang jelas, tetapi proposal sebelumnya untuk properti yang diketik tidak menyertakan properti statis. Di PHP7. 4, Anda juga dapat mendeklarasikan tipe untuk properti statis
Selanjutnya, Anda dapat mengembalikan referensi ke properti yang diketik, dan jenisnya akan tetap dihormati
class Example { public string $name; } $foo = new Example(); $foo->name = 'Apple'; $bar =& $foo->name; $bar = []; // Not allowedIni akan menimbulkan kesalahan
Fatal error: Uncaught TypeError: Cannot assign .. to reference held by property Example::$name of type .. in ...Nilai default dalam konstruktor dan deklarasi properti
Untuk alasan historis, PHP memungkinkan Anda menetapkan nilai default untuk argumen fungsi dalam deklarasinya meskipun jenisnya tidak dapat dibatalkan
Di konstruktor, kami secara eksplisit menandai bahwa class Example { public ?string $name; } $foo = new Example(); $foo->name = 'Ayesh'; // Valid $foo->name = null; // Valid0 argumen tidak dapat dibatalkan, namun PHP menerima Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8 sebagai nilai default. Perilaku ini hanya berlaku untuk Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8 nilai default. Meskipun secara semantik tidak valid, perilaku ini diperbolehkan karena alasan historis dan implementasi
Dengan properti yang diketik, ini tidak diperbolehkan
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_0Ini akan segera menimbulkan kesalahan
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_1Jenis Varians
PHP 7. 4 hadir dengan varian tipe pengembalian, yang berarti kelas anak dapat mengembalikan instance yang lebih spesifik. Ini belum didukung untuk jenis properti. Misalnya
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_2Kode di atas tidak akan berfungsi. Meskipun class Example {
public string $name;
}
$foo = new Example();
$foo->name = 420;
var_dump($foo->name);
// string(3) "420"0 adalah subset dari kelas class Example {
public string $name;
}
$foo = new Example();
$foo->name = 420;
var_dump($foo->name);
// string(3) "420"1, mengubah deklarasi tipe class Example {
public string $name;
}
$foo = new Example();
$foo->name = 420;
var_dump($foo->name);
// string(3) "420"2 tidak diperbolehkan. Anda masih dapat menetapkan instance class Example {
public string $name;
}
$foo = new Example();
$foo->name = 420;
var_dump($foo->name);
// string(3) "420"1 ke class Example {
public string $name;
}
$foo = new Example();
$foo->name = 420;
var_dump($foo->name);
// string(3) "420"2. Ini disebut class Example {
public string $name;
}
$foo = new Example();
$foo->name = 420;
var_dump($foo->name);
// string(3) "420"_5, dan sekarang didukung untuk jenis pengembalian
Mencoba hal di atas akan menimbulkan kesalahan seperti berikut
Kode berikut ini masih valid
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_4Perhatikan bagaimana deklarasi properti di class Example { public string $name; } $foo = new Example(); $foo->name = 420; var_dump($foo->name); // string(3) "420"_6 dan class Example { public string $name; } $foo = new Example(); $foo->name = 420; var_dump($foo->name); // string(3) "420"2 adalah class Example { public string $name; } $foo = new Example(); $foo->name = 420; var_dump($foo->name); // string(3) "420"1, tetapi kami menetapkan instance class Example { public string $name; } $foo = new Example(); $foo->name = 420; var_dump($foo->name); // string(3) "420"0 untuk itu
Untuk meringkas
- Anda tidak dapat mengganti kelas anak untuk properti
- Anda tidak dapat menambahkan tipe ke kelas anak jika induknya tidak menerapkan tipe
- Anda tidak dapat menandai tipe non-nullable sebagai nullable di kelas anak
- Anda tidak dapat menandai tipe nullable sebagai non-nullable di kelas anak
Untuk memvisualisasikan ini, lihat rantai pewarisan berikut. Tidak satu pun dari hal berikut yang diizinkan
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_5Di atas akan membuang kesalahan berikut (tidak bersamaan)
class Example { public $name; } $foo = new Example(); var_dump($foo->name === null); // true_6Kompatibilitas mundur
Mendeklarasikan jenis properti bersifat opsional, dan semua kode Anda yang ada akan berfungsi. Jika Anda berencana untuk memutakhirkan basis kode yang ada ke properti yang diketik, awasi status yang tidak diinisialisasi, dan pewarisan di mana aturan diterapkan dengan agak ketat. Selanjutnya, tipe properti tidak membawa perilaku warisan yang mengizinkan Fatal error: Uncaught Error: Typed property Example::$name must not be accessed before initialization in ...8 nilai dalam argumen fungsi/metodenya, dan ini bisa mengejutkan
Pikiran Akhir
Jenis properti adalah fitur yang secara pribadi membuat saya bersemangat, dan sekarang akhirnya ada di sini, saya telah menghabiskan beberapa waktu menambahkan jenis properti ke proyek pribadi saya yang sudah ada. PHPStorm 2019. 3 hadir dengan dukungan untuk semua PHP 7. 4 fitur, dan ada perbaikan cepat untuk menambahkan jenis properti jika dapat dikumpulkan dari komentar docblock properti atau dari konstruktor
Bahkan dalam proyek yang memiliki cakupan pengujian 100%, saya masih menemukan beberapa bug yang selalu ada, tetapi jenis properti membuatnya menonjol
Proyek open source mungkin membutuhkan waktu untuk membutuhkan PHP 7. 4 sebagai versi minimum, tetapi itu tidak akan menghalangi Anda untuk menggunakannya dalam proyek pribadi Anda