Liên kết tĩnh muộn
Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 36 trên 91.
Khi dùng self:: trong lớp cha, nó luôn tham chiếu đến lớp nơi nó được viết, chứ không phải lớp thực sự đang được dùng. Điều này có thể gây ra hành vi không mong muốn khi kế thừa. Liên kết tĩnh muộn giải quyết vấn đề này bằng từ khóa static::.
Xét ví dụ này, trong đó self:: không hoạt động như mong đợi:
<?php
class ParentClass {
public static function create() {
return new self();
}
public static function getClassName() {
return self::class;
}
}
class ChildClass extends ParentClass {}
$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();
Đầu ra:
ParentClass
ParentClassDù gọi ChildClass::create(), ta vẫn nhận được một đối tượng ParentClass vì self:: được xác định tại thời điểm biên dịch. Bây giờ, hãy dùng static:: thay thế:
<?php
class ParentClass {
public static function create() {
return new static();
}
public static function getClassName() {
return static::class;
}
}
class ChildClass extends ParentClass {}
$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();
Đầu ra:
ChildClass
ChildClassVới static::, PHP chờ đến khi chạy để xác định lớp nào cần dùng. Cách này gọi là liên kết muộn vì quyết định được đưa ra trễ. Đây là điều thiết yếu đối với các phương thức nhà máy và mọi phương thức tĩnh cần tuân theo kế thừa.
Điểm chính: Dùng static:: thay vì self:: khi bạn muốn các lớp con kế thừa và tùy chỉnh hành vi tĩnh đúng cách.
Thử thách
DễHãy xây dựng một hệ thống đăng ký model để minh họa sức mạnh của liên kết tĩnh muộn (late static binding). Bạn sẽ tạo một lớp cơ sở Model với một phương thức factory mà các lớp con có thể kế thừa. Nhờ static::, mỗi lớp con sẽ tạo đúng instance của chính nó thay vì của lớp cha.
Bạn sẽ sắp xếp code trong bốn tệp:
Model.php: Tạo lớp cơ sởModelvới thuộc tính tĩnh được bảo vệ$tableName, đặt thành"models". Thêm phương thức tĩnhcreate(), dùngnew static()để trả về một instance mới của lớp đã gọi phương thức đó. Thêm một phương thức tĩnh khác làgetTable(), trả vềstatic::$tableName. Cuối cùng, thêm phương thứcdescribe(), trả về"[ClassName] from table [tableName]"bằng cách dùngstatic::classvàstatic::$tableName.User.php: Tạo lớpUserkế thừaModel. Bao gồm tệp của lớp cha. Ghi đè thuộc tính tĩnh$tableNamethành"users". Lớp này kế thừa tất cả phương thức từModelmà không cần thay đổi.Product.php: Tạo lớpProductkế thừaModel. Bao gồm tệp của lớp cha. Ghi đè thuộc tính tĩnh$tableNamethành"products". Tương tự, lớp này kế thừa tất cả phương thức từ lớp cha.main.php: Bao gồm cả hai tệp User và Product. Dùng phương thức factory kế thừacreate()để tạo instance của cảUservàProduct. Với mỗi instance, gọidescribe()và in kết quả trên một dòng riêng. Sau đó, in tên bảng của mỗi lớp bằngUser::getTable()vàProduct::getTable(), mỗi kết quả trên một dòng riêng.
Điểm đặc biệt ở đây là các phương thức create() và getTable() chỉ được định nghĩa trong lớp cha Model, nhưng vẫn hoạt động chính xác với các lớp con vì static:: trì hoãn việc liên kết cho đến khi chương trình chạy. Khi bạn gọi User::create(), PHP tạo một instance User, chứ không phải instance Model, vì static:: tham chiếu đến lớp thực sự đã được gọi.
Đầu ra của bạn cần có bốn dòng: phần mô tả cho instance User, phần mô tả cho instance Product, tên bảng User và tên bảng Product.
Tự làm thử
<?php
require_once 'User.php';
require_once 'Product.php';
// TODO: Dùng phương thức (method) factory create() được kế thừa để tạo một instance User
// TODO: Dùng phương thức factory create() được kế thừa để tạo một instance Product
// TODO: Gọi describe() trên instance User và in kết quả ra
// TODO: Gọi describe() trên instance Product và in kết quả ra
// TODO: In User::getTable() ra
// TODO: In Product::getTable() ra
?>Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa $thisPhương thứcThuộc tínhHàm khởi tạo (__construct)Hàm hủy (__destruct)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnTừ khóa parent::Ghi đè phương thứcTừ khóa finalLớp trừu tượngÔn tập: hệ thống phân cấp nhân viên7Đóng gói
Công khai, được bảo vệ, riêng tưTìm hiểu sâu về bộ điều chỉnh quyền truy cậpGetter và setterẨn thông tinRút gọn hàm khởi tạo (8.0)Ôn tập: hệ thống hồ sơ học sinh2Không gian tên và tự động nạp
Giới thiệu về không gian tênTừ khóa useChuẩn tự động nạp PSR-4Trình tự động nạp của ComposerÔn tập: dự án có tổ chức5Giao diện và hợp đồng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnGiao diện và lớp trừu tượngGợi ý kiểu với giao diệnÔn tập: Máy tính hình học8Phương thức ma thuật
Giới thiệu về phương thức ma thuật__toString và __debugInfo__get, __set, __isset, __unset__call và __callStatic__clone và sao chép đối tượng__serialize và __unserializeÔn tập: Bộ sưu tập tùy chỉnh3Thuộc tính của lớp
Thuộc tính instance và staticHằng số trong lớpPhương thức và thuộc tính staticThuộc tính private và protectedThuộc tính chỉ đọc (PHP 8.1)Ôn tập: Trình quản lý tài khoản ngân hàng6Đa hình
Xem lại việc ghi đè phương thứcĐa hình qua giao diệnGợi ý kiểu và kiểu hợpLiên kết tĩnh muộnÔn tập: bộ xử lý thanh toánTự luyện tập: Trình biên dịch PHP online