Ini cerita yang panjang dan menyedihkan.
Ketika PHP 5.2 pertama kali memperkenalkan peringatan ini, binding statis terbaru belum ada dalam bahasa tersebut. Jika Anda tidak terbiasa dengan binding statis yang terlambat, perhatikan bahwa kode seperti ini tidak berfungsi seperti yang Anda harapkan:
<?php
abstract class ParentClass {
static function foo() {
echo "I'm gonna do bar()";
self::bar();
}
abstract static function bar();
}
class ChildClass extends ParentClass {
static function bar() {
echo "Hello, World!";
}
}
ChildClass::foo();
Mengesampingkan peringatan mode ketat, kode di atas tidak berfungsi. The self::bar()
panggilan foo()
eksplisit mengacu pada bar()
metode ParentClass
, bahkan ketika foo()
disebut sebagai metode ChildClass
. Jika Anda mencoba menjalankan kode ini dengan mode ketat nonaktif, Anda akan melihat " Kesalahan fatal PHP: Tidak dapat memanggil metode abstrak ParentClass :: bar () ".
Mengingat ini, metode statis abstrak di PHP 5.2 tidak berguna. The Seluruh titik menggunakan metode abstrak adalah bahwa Anda dapat menulis kode yang memanggil metode tanpa mengetahui apa implementasi itu akan menjadi menelepon - dan kemudian memberikan implementasi yang berbeda pada anak kelas yang berbeda. Tetapi karena PHP 5.2 tidak menawarkan cara yang bersih untuk menulis metode kelas induk yang memanggil metode statis kelas anak tempat ia dipanggil, penggunaan metode statis abstrak ini tidak dimungkinkan. Karenanya setiap penggunaan abstract static
dalam PHP 5.2 adalah kode yang buruk, mungkin terinspirasi oleh kesalahpahaman tentang cara kerja self
kata kunci. Sangat masuk akal untuk memberikan peringatan atas hal ini.
Tapi kemudian PHP 5.3 datang ditambahkan dalam kemampuan untuk merujuk ke kelas di mana metode dipanggil melalui static
kata kunci (tidak seperti self
kata kunci, yang selalu mengacu pada kelas di mana metode itu didefinisikan ). Jika Anda mengubah self::bar()
ke static::bar()
dalam contoh saya di atas, ini berfungsi dengan baik di PHP 5.3 dan di atasnya. Anda dapat membaca lebih lanjut tentang self
vs static
at New self vs. new static .
Dengan kata kunci statis ditambahkan, argumen yang jelas untuk abstract static
mengeluarkan peringatan telah hilang. Tujuan utama pengikatan statis akhir adalah untuk memungkinkan metode yang didefinisikan dalam kelas induk untuk memanggil metode statis yang akan didefinisikan dalam kelas anak; memungkinkan metode statis abstrak tampaknya masuk akal dan konsisten mengingat adanya binding statis terlambat.
Anda masih bisa, saya kira, membuat alasan untuk menjaga peringatan itu. Misalnya, Anda dapat berargumen bahwa karena PHP memungkinkan Anda memanggil metode statis kelas abstrak, dalam contoh saya di atas (bahkan setelah memperbaikinya dengan menggantinya self
dengan static
) Anda mengekspos metode publik ParentClass::foo()
yang rusak dan Anda tidak benar-benar ingin melakukannya. membuka. Menggunakan kelas non-statis - yaitu, membuat semua metode contoh metode dan membuat turunan dari ParentClass
semua menjadi lajang atau sesuatu - akan menyelesaikan masalah ini, karena ParentClass
, menjadi abstrak, tidak dapat dipakai dan metode contoh tidak bisa disebut. Saya pikir argumen ini lemah (karena saya pikir mengeksposParentClass::foo()
bukan masalah besar dan menggunakan lajang daripada kelas statis sering kali tidak perlu bertele-tele dan jelek), tetapi Anda mungkin cukup tidak setuju - ini adalah panggilan yang agak subjektif.
Jadi berdasarkan argumen ini, pengembang PHP menyimpan peringatan dalam bahasa, bukan?
Uh, tidak juga .
Laporan bug PHP 53081, ditautkan di atas, meminta peringatan untuk dihapus karena penambahan static::foo()
konstruksi telah membuat metode statis abstrak menjadi wajar dan berguna. Rasmus Lerdorf (pencipta PHP) memulai dengan memberi label permintaan palsu dan melewati rantai panjang alasan yang buruk untuk mencoba membenarkan peringatan tersebut. Kemudian, akhirnya, pertukaran ini terjadi:
Giorgio
saya tahu tapi:
abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}
class cB extends cA
{
static function B(){echo "ok";}
}
cB::A();
Rasmus
Benar, begitulah seharusnya cara kerjanya.
Giorgio
tapi tidak diperbolehkan :(
Rasmus
Apa yang tidak diperbolehkan?
abstract class cA {
static function A(){static::B();}
abstract static function B();
}
class cB extends cA {
static function B(){echo "ok";}
}
cB::A();
Ini bekerja dengan baik. Anda jelas tidak bisa memanggil self :: B (), tapi static :: B () baik-baik saja.
Klaim Rasmus bahwa kode dalam contohnya "berfungsi dengan baik" adalah salah; seperti yang Anda ketahui, itu melontarkan peringatan mode ketat. Saya kira dia sedang menguji tanpa mode ketat dihidupkan. Terlepas dari itu, Rasmus yang bingung meninggalkan permintaan yang ditutup secara keliru sebagai "palsu".
Dan itulah mengapa peringatan itu masih dalam bahasa. Ini mungkin bukan penjelasan yang sepenuhnya memuaskan - Anda mungkin datang ke sini berharap ada pembenaran rasional dari peringatan itu. Sayangnya, di dunia nyata, terkadang pilihan lahir dari kesalahan duniawi dan penalaran yang buruk daripada dari pengambilan keputusan yang rasional. Ini hanyalah salah satu saat itu.
Untungnya, Nikita Popov telah menghapus peringatan dari bahasa di PHP 7 sebagai bagian dari PHP RFC: Reclassify E_STRICT notices . Pada akhirnya, kewarasan telah menang, dan begitu PHP 7 dirilis, kita semua dapat dengan senang hati menggunakannya abstract static
tanpa menerima peringatan konyol ini.