Apa sebenarnya binding statis terlambat di PHP?
Jawaban:
Anda pasti perlu membaca Late Static Bindings di manual PHP. Namun, saya akan mencoba memberi Anda ringkasan singkat.
Pada dasarnya, ini bermuara pada fakta bahwa self
kata kunci tidak mengikuti aturan pewarisan yang sama. self
selalu menetapkan kelas yang digunakan. Artinya jika Anda membuat metode di kelas induk dan memanggilnya dari kelas anak, self
tidak akan mereferensikan anak seperti yang Anda harapkan.
Pengikatan statis akhir memperkenalkan penggunaan baru untuk static
kata kunci, yang membahas kekurangan khusus ini. Saat Anda menggunakannya static
, ini mewakili kelas tempat Anda pertama kali menggunakannya, yaitu. itu 'mengikat' ke kelas runtime.
Itulah dua konsep dasar di baliknya. Cara self
, parent
dan static
pengoperasian saat static
sedang dimainkan bisa jadi tidak kentara, jadi daripada membahas lebih detail, saya sangat menyarankan Anda mempelajari contoh halaman manual. Setelah Anda memahami dasar-dasar setiap kata kunci, contoh sangat diperlukan untuk melihat hasil seperti apa yang akan Anda dapatkan.
self
kata kunci tidak mengikuti aturan pewarisan. self
selalu menentukan kelas penggunaannya." - Yang tidak berarti Anda tidak dapat memanggil metode statis induk dari objek anak melalui self
, seperti metode non-statis. Anda mungkin bermaksud benar, tetapi Anda harus mengulanginya kembali. Itu semua hanya benar-benar penting setelah anak-anak memiliki nama anggota yang identik karena Anda kemudian dapat memutuskan mana yang akan dirujuk dengan menggunakan static::
sebagai gantinya.
Dari PHP: Late Static Bindings - Manual :
Pada PHP 5.3.0, PHP mengimplementasikan fitur yang disebut pengikatan statis akhir yang dapat digunakan untuk mereferensikan kelas yang dipanggil dalam konteks pewarisan statis.
Pengikatan statis akhir mencoba untuk memecahkan batasan itu dengan memperkenalkan kata kunci yang mereferensikan kelas yang awalnya dipanggil saat runtime. ... Diputuskan untuk tidak memperkenalkan kata kunci baru, melainkan menggunakan
static
yang sudah dipesan.
Mari kita lihat contohnya:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
Binding statis terlambat bekerja dengan menyimpan kelas yang dinamai dalam "panggilan non-penerusan" terakhir. Dalam kasus pemanggilan metode statis, ini adalah kelas yang dinamai secara eksplisit (biasanya yang ada di sebelah kiri
::
operator); dalam kasus pemanggilan metode non-statis, itu adalah kelas dari objek. Sebuah "call forwarding" adalah salah satu statis yang diperkenalkan olehself::
,parent::
,static::
, atau, jika naik dalam hirarki kelas,forward_static_call()
. Fungsiget_called_class()
ini dapat digunakan untuk mengambil string dengan nama kelas yang dipanggil danstatic::
memperkenalkan cakupannya.
Tidak ada perilaku yang sangat jelas:
Kode berikut menghasilkan 'alphabeta'.
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
Namun, jika kita menghapus deklarasi fungsi nama kelas dari kelas beta, kita mendapatkan 'alphaalpha' sebagai hasilnya.
Saya mengutip dari buku: "PHP Master menulis kode mutakhir".
Pengikatan statis akhir adalah fitur yang diperkenalkan dengan php 5.3. Ini memungkinkan kita untuk mewarisi metode statis dari kelas induk, dan untuk merujuk kelas anak yang dipanggil.
Ini berarti Anda bisa memiliki kelas abstrak dengan metode statis, dan mereferensikan implementasi konkret kelas anak dengan menggunakan notasi static :: method () alih-alih self :: method ().
Jangan ragu untuk melihat dokumentasi resmi php juga: http://php.net/manual/en/language.oop5.late-static-bindings.php
Cara paling jelas untuk menjelaskan Late Static Binding adalah dengan contoh sederhana. Perhatikan dua definisi kelas di bawah ini, dan baca terus.
class Vehicle {
public static function invokeDriveByStatic() {
return static::drive(); // Late Static Binding
}
public static function invokeStopBySelf() {
return self::stop(); // NOT Late Static Binding
}
private static function drive(){
return "I'm driving a VEHICLE";
}
private static function stop(){
return "I'm stopping a VEHICLE";
}
}
class Car extends Vehicle {
protected static function drive(){
return "I'm driving a CAR";
}
private static function stop(){
return "I'm stopping a CAR";
}
}
Kami melihat Kelas Orang Tua (Kendaraan) dan Kelas Anak (Mobil). Kelas Parent memiliki 2 metode publik:
invokeDriveByStatic
invokeStopBySelf
Kelas Parent juga memiliki 2 metode privat:
drive
stop
Kelas Anak mengesampingkan 2 metode:
drive
stop
Sekarang mari panggil metode publik:
invokeDriveByStatic
invokeStopBySelf
Tanyakan pada diri Anda: Kelas mana yang meminta invokeDriveByStatic
/ invokeStopBySelf
? Kelas Orang Tua atau Anak?
Lihat di bawah ini:
// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE
// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR
// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE
Kata static
kunci digunakan dalam pola desain Singleton. Lihat tautan: https://refactoring.guru/design-patterns/singleton/php/example
Contoh paling sederhana untuk menunjukkan perbedaannya.
Catatan, diri :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Pengikatan statis terlambat, perhatikan statis :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
Melihatnya dari pertanyaan "mengapa saya menggunakan ini?" perspektif, ini pada dasarnya adalah cara untuk mengubah konteks dari mana metode statis sedang diinterpretasikan / dijalankan.
Dengan self
, konteksnya adalah tempat Anda mendefinisikan metode aslinya. Dengan static
, itu yang Anda panggil.
Juga, perhatikan jika Anda memperbarui variabel statis di kelas anak. Saya menemukan ini (agak) hasil yang tidak terduga di mana anak B memperbarui anak C:
class A{
protected static $things;
}
class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}
class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}
print_r(C::things());
// Array (
// [2] => Thing C
// )
B::things();
print_r(C::things());
// Array (
// [2] => Thing C
// [1] => Thing B
// )
Anda dapat memperbaikinya dengan mendeklarasikan variabel yang sama di setiap kelas anak, misalnya:
class C extends A{
protected static $things; // add this and B will not interfere!
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}