Kế thừa trong PHP
Khi khai báo tạo ra các lớp mới, chúng có thể kế thừa lại các thuộc tính và phương thức có trong một lớp khác. Lớp kế thừa lại thuộc tính phương thức gọi là lớp con (subclass). Lớp mà lớp con kế thừa lại gọi là lớp cha (parent class). Bạn sử dụng từ khóa extends để khai báo kế thừa, cú pháp như sau:
class ChildClass extends ParentClass { ... }
Ví dụ về kế thừa lớp trong PHP
// Lớp Pet không kế thừa lớp nào class Pet { public $name; function __construct($pet_name) { $this->name = $pet_name; } function eat() { echo "$this->name is eating."; } function play() { echo "$this->name is playing."; } }
// Lớp Cat kế thừa lớp Pet class Cat extends Pet { function play() { echo "$this->name is climbing."; } function sleep() { echo "$this->name is sleeping."; } function eat_play() { $this->eat(); $this->play(); } }
// Lớp Dog kế thừa lớp Pet class Dog extends Pet { function play() { echo "$this->name is fetching."; } }
Sử dụng:
$dog = new Dog('Leo'); $cat = new Cat('Luna'); $pet = new Pet('Bella'); $dog->eat(); // Leo is eating. $cat->eat(); // Luna is eating. $pet->eat(); // Bella is eating. $dog->play(); // Leo is fetching. $cat->play(); // Luna is climbing. $pet->play(); // Bella is playing. $cat->sleep(); // Luna is climbing.
Nhận xét: Lớp Cat kế thừa từ lớp Pet, do vậy trong lớp Cat có luôn các thuộc tính ($name) và phương thức của Pet (eat, play). Pet gọi là lớp cha, Cat là lớp con. Trong lớp con thoải mái khai báo thêm các thuộc tính và phương thức khác, lớp Cat có thêm phương thức sleep.
Chỉ các phương thức, thuộc tính là public và protected lớp con kế thừa trực tiếp, các thành viên private không thể truy cập từ lớp con.
Nạp chồng (overriding) phương thức
Khi kế thừa lớp cha, một lớp chon có thể định nghĩa lại một phương thức đã có trong lớp cha, việc này gọi là nạp chồng (khi nạp chồng cần khai báo lại đúng tên và tham số phương thức). Trong ví dụ trên, lớp Dog và Cat đã định nghĩa lại phương thức play chứ không dùng lại của lớp cha.
Chú ý: khi lớp con nạp chồng một phương thức, thì nội bộ lớp cha cũng sẽ sử dụng phương thức nạp chồng này. Hay xem phương thức eat_play
$cat = new Cat('Luna'); $cat->eat_play(); // Luna is eating. Luna is climbing.
eat_play định nghĩa trong lớp cha, bên trong nó gọi hàm play, nhưng hàm play bị lớp con định nghĩa lại nên eat_play không dùng hàm play trong lớp cha mà dùng play trong lớp con.
Cũng cần chú ý là phương thức khởi tạo __construct cũng bị nạp chồng bình thường nên nếu nạp chồng __construct cần chú ý logic khởi tạo đối tượng cho đúng. Xem phần sau.
Gọi phương thức ở lớp cha
Trong lớp con, nếu muốn gọi một phương thức định nghĩa trong lớp cha thì dùng từ khóa parent và toán tử phân giải phạm vi :: (Scope Resolution Operator)
Ví dụ, định nghĩa lại lớp Cat như sau:
class Cat extends Pet { protected $age; function __construct(string $pet_name, int $age) { // Gọi phương thức khởi tạo của lớp cha parent::__construct($pet_name); $this->age = $age; } function play() { // Gọi phương thức play của lớp cha parent::play(); echo "$this->name is climbing and it's $this->age year old."; } }
$cat = new Cat("Luna", 5); $cat->play(); // Luna is playing. Luna is climbing and it's 5 year old.
Lớp và phương thức final
Lớp khai báo có dùng từ khóa final để khai báo (gọi là lớp final) thì lớp đó không thể dùng làm lớp cha cho bất kỳ lớp nào. Lớp final là lớp không thể kế thừa, chỉ dùng để tạo ra đối tượng.
final class A { } class B extends A { } // Lỗi không chạy được, thông báo lỗi: // Fatal error: Class B may not inherit from final class (A) in /
Tương tự, một phương thức trong lớp cha khai báo là final thì nó không thể bị nạp chồng (định nghĩa lại bởi lớp con).
class X { // Phương thức này là final, lớp con không được override final public function hello() { } }