Đặc tính và kế thừa
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 55 trên 91.
Giờ bạn đã hiểu trait hoạt động như thế nào, hãy cùng làm rõ khi nào nên dùng trait và khi nào nên dùng kế thừa. Cả hai đều cho phép tái sử dụng code, nhưng phục vụ những mục đích khác nhau và có các đặc điểm riêng.
Kế thừa thiết lập mối quan hệ “là một”. Lớp Dog kế thừa lớp Animal nghĩa là chó là một loài vật. Lớp con kế thừa danh tính của lớp cha và có thể được dùng ở bất cứ đâu cần kiểu của lớp cha.
Đặc tính cung cấp khả năng “có”. Khi một lớp sử dụng đặc tính Loggable, lớp đó có chức năng ghi nhật ký, nhưng không trở thành bộ ghi nhật ký. Đặc tính bổ sung hành vi mà không thay đổi bản chất của lớp.
<?php
// Kế thừa: Dog là một Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Dog có khả năng ghi nhật ký
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
Những điểm khác biệt chính cần ghi nhớ:
| Khía cạnh | Kế thừa | Traits |
|---|---|---|
| Mối quan hệ | là một | có khả năng |
| Giới hạn | Chỉ có một lớp cha | Có thể dùng nhiều trait |
| Kiểm tra kiểu dữ liệu | Hoạt động với instanceof | Không có định danh kiểu |
| Phù hợp nhất với | Các mối quan hệ phân cấp | Các hành vi dùng chung giữa những lớp không liên quan |
Dùng kế thừa khi các lớp có chung một đặc điểm nhận dạng. Dùng trait khi các lớp không liên quan cần cùng một chức năng mà không thuộc cùng một hệ thống phân cấp.
Thử thách
DễHãy xây dựng một hệ thống phương tiện để minh họa khi nào nên dùng kế thừa thay vì trait. Bạn sẽ tạo một hệ thống phân cấp các phương tiện có chung danh tính thông qua kế thừa, đồng thời bổ sung các khả năng dùng chung thông qua trait.
Bạn sẽ sắp xếp code trong bốn tệp:
Trackable.php: Tạo một trait tên làTrackablecó khả năng theo dõi GPS. Trait này cần có:- Thuộc tính riêng tư
$location(chuỗi) - Phương thức
setLocation(string $location)lưu vị trí hiện tại - Phương thức
getLocation()trả về"Location: [location]"
- Thuộc tính riêng tư
Vehicle.php: Tạo một lớp cơ sởVehicleđể thiết lập quan hệ «là». Thêm tệp trait vào. Dùng cú pháp khai báo thuộc tính trong hàm khởi tạo để định nghĩa thuộc tính$brandvới phạm vi protected. Thêm phương thứcdescribe()trả về"Vehicle: [brand]". Lớp này nên dùng traitTrackablevì mọi phương tiện trong đội xe của chúng ta đều có GPS.Car.php: Tạo lớpCarkế thừaVehicle. Thêm tệp Vehicle vào. Dùng cú pháp khai báo thuộc tính trong hàm khởi tạo để nhận thương hiệu và thuộc tính riêng tư$doors(số nguyên). Gọi hàm khởi tạo của lớp cha với thương hiệu. Ghi đè phương thứcdescribe()để trả về"Car: [brand] with [doors] doors".main.php: Thêm tệp Car vào. Bạn sẽ nhận ba đầu vào: tên thương hiệu, số cửa và một chuỗi chỉ vị trí. Tạo một đối tượngCar, đặt vị trí cho đối tượng đó, sau đó in ra hai dòng:- Kết quả gọi
describe() - Kết quả gọi
getLocation()
- Kết quả gọi
Hãy chú ý cách kế thừa và trait kết hợp với nhau ở đây: Car là một Vehicle (kế thừa xác lập danh tính), còn Vehicle có khả năng theo dõi (trait bổ sung hành vi). Bạn có thể dùng instanceof Vehicle để kiểm tra xem một thứ có phải là phương tiện hay không, nhưng không có kiểu «Trackable» để kiểm tra: đó là điểm khác biệt chính giữa hai cách tiếp cận này.
Tự làm thử
<?php
// Tệp chính: tạo và kiểm tra instance Car
// TODO: Nạp tệp Car.php
// Đọc dữ liệu đầu vào
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));
// TODO: Tạo instance Car với brand và doors
// TODO: Đặt vị trí của xe
// TODO: In ra kết quả của describe()
// TODO: In ra kết quả của getLocation()
?>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