Menu
CoddyTech

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
ParentClass

Dù 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
ChildClass

Vớ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.

challenge icon

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ở Model với thuộc tính tĩnh được bảo vệ $tableName, đặt thành "models". Thêm phương thức tĩnh create(), dùng new 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ức describe(), trả về "[ClassName] from table [tableName]" bằng cách dùng static::class và static::$tableName.
  • User.php: Tạo lớp User kế thừa Model. Bao gồm tệp của lớp cha. Ghi đè thuộc tính tĩnh $tableName thành "users". Lớp này kế thừa tất cả phương thức từ Model mà không cần thay đổi.
  • Product.php: Tạo lớp Product kế thừa Model. Bao gồm tệp của lớp cha. Ghi đè thuộc tính tĩnh $tableName thà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ừa create() để tạo instance của cả User và Product. Với mỗi instance, gọi describe() 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ằng User::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

?>
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch PHP online