Câu trả lời:
Bạn chắc chắn cần phải đọc các ràng buộc tĩnh muộn trong hướng dẫn sử dụng PHP. Tuy nhiên, tôi sẽ cố gắng cung cấp cho bạn một bản tóm tắt nhanh chóng.
Về cơ bản, nó đi sâu vào thực tế là self
từ khóa không tuân theo các quy tắc thừa kế tương tự. self
luôn luôn giải quyết lớp mà nó được sử dụng. Điều này có nghĩa là nếu bạn tạo một phương thức trong lớp cha và gọi nó từ lớp con, self
sẽ không tham chiếu đến đứa trẻ như bạn mong đợi.
Liên kết tĩnh muộn giới thiệu một cách sử dụng mới cho static
từ khóa, giải quyết thiếu sót đặc biệt này. Khi bạn sử dụng static
, nó đại diện cho lớp nơi bạn sử dụng lần đầu tiên, nghĩa là. nó 'liên kết' với lớp thời gian chạy.
Đó là hai khái niệm cơ bản đằng sau nó. Cách self
, parent
và static
hoạt động khi static
là trong vở kịch có thể tinh tế, vì vậy thay vì đi vào chi tiết hơn, tôi muốn khuyên bạn nghiên cứu các ví dụ trang hướng dẫn. Khi bạn hiểu những điều cơ bản của từng từ khóa, các ví dụ khá cần thiết để xem bạn sẽ nhận được loại kết quả nào.
self
từ khóa không tuân theo quy tắc thừa kế. self
Luôn giải quyết theo lớp mà nó được sử dụng." - Điều đó không có nghĩa là bạn không thể gọi phương thức tĩnh của cha mẹ từ một đối tượng con thông qua self
, giống như với các phương thức không tĩnh. Bạn có thể có nghĩa là đúng, nhưng bạn nên diễn đạt lại. Tất cả chỉ thực sự quan trọng khi trẻ em có tên thành viên giống hệt nhau vì sau đó bạn có thể quyết định nên tham khảo cái nào bằng cách sử dụng static::
thay thế.
Từ PHP: Ràng buộc tĩnh muộn - Hướng dẫn :
Kể từ phiên bản PHP 5.3.0, PHP triển khai một tính năng gọi là liên kết tĩnh muộn có thể được sử dụng để tham chiếu lớp được gọi trong bối cảnh kế thừa tĩnh.
Liên kết tĩnh muộn cố gắng giải quyết giới hạn đó bằng cách giới thiệu một từ khóa tham chiếu lớp được gọi ban đầu khi chạy. ... Nó đã được quyết định không giới thiệu một từ khóa mới, mà là sử dụng
static
đã được bảo lưu.
Hãy xem một ví dụ:
<?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
?>
Các ràng buộc tĩnh muộn hoạt động bằng cách lưu trữ lớp có tên trong "cuộc gọi không chuyển tiếp" cuối cùng. Trong trường hợp gọi phương thức tĩnh, đây là lớp được đặt tên rõ ràng (thường là lớp bên trái
::
toán tử); trong trường hợp gọi phương thức không tĩnh, nó là lớp của đối tượng. Một "cuộc gọi chuyển tiếp" là một trong những tĩnh được giới thiệu bởiself::
,parent::
,static::
, hoặc, nếu đi lên trong hệ thống phân cấp lớp,forward_static_call()
. Hàm nàyget_called_class()
có thể được sử dụng để truy xuất một chuỗi có tên của lớp được gọi vàstatic::
giới thiệu phạm vi của nó.
Không có hành vi rất rõ ràng:
Đoạn mã sau tạo ra '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
Tuy nhiên, nếu chúng ta xóa khai báo của hàm classname khỏi lớp beta, chúng ta sẽ nhận được 'alphaalpha'.
Tôi đang trích dẫn từ cuốn sách: "PHP Master viết mã tiên tiến".
Liên kết tĩnh muộn là một tính năng được giới thiệu với php 5.3. Nó cho phép chúng ta kế thừa các phương thức tĩnh từ một lớp cha và tham chiếu lớp con được gọi.
Điều này có nghĩa là bạn có thể có một lớp trừu tượng với các phương thức tĩnh và tham chiếu các triển khai cụ thể của lớp con bằng cách sử dụng ký hiệu static :: method () thay vì self :: method ().
Vui lòng xem tài liệu php chính thức: http://php.net/manual/en/lingu.oop5.late-static-bindings.php
Cách rõ ràng nhất để giải thích Binding tĩnh muộn là với một ví dụ đơn giản. Hãy xem hai định nghĩa lớp dưới đây và đọc tiếp.
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";
}
}
Chúng tôi thấy Lớp phụ huynh (Xe cộ) và Lớp trẻ em (Xe hơi). Lớp Phụ huynh có 2 phương thức chung:
invokeDriveByStatic
invokeStopBySelf
Lớp Phụ huynh cũng có 2 phương thức riêng:
drive
stop
Lớp con ghi đè 2 phương thức:
drive
stop
Bây giờ hãy gọi các phương thức công khai:
invokeDriveByStatic
invokeStopBySelf
Hãy tự hỏi: Lớp nào gọi invokeDriveByStatic
/ invokeStopBySelf
? Lớp Phụ huynh hay Trẻ em?
Hãy xem bên dưới:
// 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
Các static
từ khóa được sử dụng trong một mẫu thiết kế Singleton. Xem liên kết: https://refactoring.guru/design-potypes/singleton/php/example
Ví dụ đơn giản nhất để thể hiện sự khác biệt.
Lưu ý, tự :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Liên kết tĩnh muộn, lưu ý tĩnh :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
Ngoài ra, xem nếu bạn cập nhật các biến tĩnh trong các lớp con. Tôi tìm thấy kết quả bất ngờ này (phần nào) khi con B cập nhật con 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
// )
Bạn có thể sửa nó bằng cách khai báo cùng một biến trong mỗi lớp con, ví dụ:
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;
}
}