[BÀI 31] KẾ THỪA TRONG PHP
Kế thừa là gì: Kế thừa trong php được hiểu là class này có thể sử dụng lại các thuộc tính, phương thức của class khác mà không cần viết lại từ đầu. Mỗi thuộc tính, phương thức chỉ cần viết một lần duy nhất và có thể chia sẻ thông tin với class khác nhờ sự kế thừa. Class cho các class khác kế ...
Kế thừa là gì:
Kế thừa trong php được hiểu là class này có thể sử dụng lại các thuộc tính, phương thức của class khác mà không cần viết lại từ đầu. Mỗi thuộc tính, phương thức chỉ cần viết một lần duy nhất và có thể chia sẻ thông tin với class khác nhờ sự kế thừa.
Class cho các class khác kế thừa được gọi là class cha, class được kế thừa gọi là class con. Ngôn ngữ PHP cho phép đa kế thừa, tức là class A có thể kế thừa từ class B, class B có thể kế thừa từ class C….
Khi class A kế thừa từ class B, class A sẽ có tất cả các thuộc tính, phương thức của class B, ngoài ra class A còn có thể có các phương thức, thuộc tính mới hoặc loại bỏ đi một số thuộc tính, phương thức của class B. Tôi gọi đây là kế thừa có chọn lọc. Class A chỉ lấy những cái mình cần từ class B, và tạo nên các thuộc tính mới, phương thức mới, thể hiện cá tính và chức năng của mình.
Không phải class nào cũng cho class khác kế thừa, để quy định điều này chúng ta sử dụng các từ khóa mà PHP đã định sẵn.
Cú pháp kế thừa trong PHP:
class A extends class B{…}
Trong đó “extends” là từ khóa khai báo có sự kế thừa.
Tôi lấy một ví dụ đơn giản tôi có class xe, class xe là class quản lý chung tất cả các loại xe (xe đạp, xe máy, ô tô,…) ,class xe chứa các đặc điểm chung mà tất cả các loại xe đều có, như là bánh xe, màu sắc, vận tốc. Và tôi có 1 class là xe máy kế thừa từ class xe, tôi không cần viết lại bánh xe, màu sắc, và vận tốc nữa, và có thể dùng luôn những thứ đã khai báo ở class xe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php //class xe là class cha: class xe{ public $mausac = "Màu vàng"; public function banhxe(){ return "Bánh xe làm bằng kim cương"; } public function vantoc(){ return "Vận tốc mà tôi đạt được là 2000km/h"; } } //class xe máy là class con: class xemay extends xe{ public function mausacxemay(){ return $this->mausac; } } //khởi tạo class xe máy: $xm = new xemay; //in ra màu sắc của xe máy: echo $xm->mausacxemay(); //in ra vận tốc mà xe máy có thể đạt được: echo "<br>".$xm->vantoc(); ?> |
Trong class “xemay” tôi không khai báo phương thức nào hết, nhưng lúc gọi hàm tôi vẫn gọi được, lý do là class “xemay” đã được kế thừa từ class “xe” và có tất cả những gì class “xe” có.
Nạp chồng:
Nạp chồng sử dụng khi class con muốn thay đổi các thuộc tính, phương thức của lớp cha. Như ví dụ ở trên, tôi có in ra vận tốc của xe máy thì sẽ in ra vận tốc là 2000km/h. bây giờ tôi muốn sửa lại vận tốc này. Tôi phải nạp chồng (ghi đè) lại phương thức vận tốc bằng cách tạo 1 function mới trong class con có tên trùng với function muốn ghi đè ở lớp cha.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php //class xe là class cha: class xe{ public $mausac = "Màu vàng"; public function banhxe(){ return "Bánh xe làm bằng kim cương"; } public function vantoc(){ return "Vận tốc mà tôi đạt được là 2000km/h"; } } //class xe máy là class con: class xemay extends xe{ public function vantoc(){ return "Tôi là xe máy và vận tốc của tôi là 9000km/h"; } } //khởi tạo class xe máy: $xm = new xemay; //in ra vận tốc mà xe máy có thể đạt được: echo "<br>".$xm->vantoc(); ?> |
Có thể thấy là tôi đã viết một hàm có tên là vận tốc (vantoc), ở class con và hàm này trùng tên với 1 hàm có trong class cha. Do vậy mà vận tốc của xe máy bây giờ là 9000 chứ không phải 2000 như trước nữa.
Trong trường hợp tôi muốn khai báo thêm thuộc tính, phương thức ở class con nhưng vẫn sử dụng những cái ở class cha, lúc này tôi sử dụng từ khóa parent để thực thi thuộc tính/phương thức ở class cha, sau đó tôi ghi thêm những thuộc tính, phương thức mà class con có. Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php //class xe là class cha: class xe{ public $mausac = "Màu vàng"; public function banhxe(){ return "Bánh xe làm bằng kim cương"; } public function vantoc(){ echo "Vận tốc của tất cả các loại xe ở Devpro là 2000km/h"; } } //class xe máy là class con: class xemay extends xe{ public function vantoc(){ parent::vantoc(); return "Tôi là xe máy và vận tốc của tôi là 9000km/h"; } } //khởi tạo class xe máy: $xm = new xemay; //in ra vận tốc mà xe máy có thể đạt được: echo "<br>".$xm->vantoc(); ?> |
Class xe máy đã lấy được nội dung của phương thức vantoc() ở class cha và khai báo thêm một thuộc tính mới, thể hiện đặc tính riêng biệt của xe máy để có thể phân biệt với các loại xe khác.
Không cho class khác kế thừa:
Một số class bạn không muốn các class khác kế thừa thì chỉ cần thêm từ khóa final ở ngay trước. Ví dụ:
final class xe(){…}
final function vantoc(){…}
Tại sao phải chống kế thừa: khi kế thừa, thì class con có khả năng thay đổi,bổ sung lại nội dung của class cha. Những file như file kết nối database (có lưu mật khẩu, tài khoản,…). Chúng ta phải chống kế thừa, tránh việc tài khoản mật khẩu bị thay đổi.
Lớp Abstract trong PHP:
Abstract là một lớp trừu tượng.
Lớp trừu tượng là lớp chứa các thuộc tính/phương thức trừu tượng.
Lớp trừu tượng, thuộc tính trừu tượng, phương thức trừu tượng bắt đầu bằng từ khóa abstract.
Thuộc tính/phương thức trừu tượng là các thuộc tính/phương thức không rõ ràng, chúng chỉ được khai báo tên, mà chưa được định nghĩa rõ ràng (là các thuộc tính/phương thức rỗng). Ví dụ tôi chắc chắn rằng ở biển Nha Trang sẽ có đặc sản riêng, chắc chắn sẽ có đặc sản nhưng tôi không biết chính xác đặc sản ở Nha Trang có những gì, và chúng như thế nào. Tôi khai báo một phương thức chung chung (phương thức trừu tượng) là đặc sản, phương thức này tôi không ghi gì hết. Và việc của những người đã từng ở Nha Trang là họ biết các đặc sản ở đây và họ sẽ thực hiện quảng cáo đặc sản của họ. Tức là họ tiến hành mô tả chi tiết các đặc sản của họ. Hay đơn giản là họ định nghĩa lại thuộc tính/phương thức trừu tượng mà tôi đã khai báo.
Abstract cũng là một class cho các class khác kế thừa. Song có một đặc điểm quan trọng mà chúng ta cần lưu ý đó là ở lớp Abstract sẽ có các thuộc tính/phương thức bắt buộc class con của nó phải đi định nghĩa lại. Chẳng hạn như xe phải có bánh xe, nếu không có bánh xe sẽ tạo nên lỗi. Class cha sẽ khai báo phương thức trừu tượng là bánh xe, và class con bắt buộc phải đi định nghĩa lại phương thức bánh xe này. Mỗi class con sẽ có một phương thức bánh xe khác nhau, do vậy tạo nên các đặc tính riêng biệt của các loại xe. Chẳng hạn, bánh xe máy sẽ khác bánh xe đạp sẽ khác bánh xe ô tô.
Lớp Abstract: ngoài việc chứa các thuộc tính/phương thức trửu tượng còn có thể có các thuộc tính/phương thức bình thường.
Lớp con kế thừa từ lớp abstract cũng sử dụng từ khóa extends.
Ví dụ: tôi bắt buộc tất cả các loại xe đều phải có bánh xe, và như ví dụ sau, trong class con tôi không định nghĩa lại phương thức trừu tượng bánh xe thì sẽ xảy ra lỗi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php //class xe là class cha: abstract class xe{ abstract function banhxe(); } //class xe máy là class con: class xemay extends xe{ } //khởi tạo class xe máy: $xm = new xemay; //in ra bánh xe của xe máy: echo $xm->banhxe(); //kết quả sẽ xảy ra lỗi do chưa định nghĩa lại banhxe() ?> |
Để không xảy ra lỗi, bắt buộc tôi phải đi định nghĩa lại phương thức banhxe() ở class con:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php //class xe là class cha: abstract class xe{ abstract function banhxe(); } //class xe máy là class con: class xemay extends xe{ public function banhxe(){ return "Bánh xe của xe máy làm bằng bạch kim :v"; } } //khởi tạo class xe máy: $xm = new xemay; //in ra bánh xe của xe máy: echo $xm->banhxe(); //kết quả sẽ không có lỗi ?> |
Lớp interface trong php:
Về bản chất lớp interface cũng là một lớp có khả năng cho lớp khác kếthừa. Khác với abstract, lớp interface không được phép có các thuộc tính/phương thức bình thường.
Lớp con của lớp interface cũng bắt buộc phải định nghĩa lại các thuộc tính/phương thức của class cha. Nếu không định nghĩa lại sẽ gặp lỗi.
Lớp con kế thừa từ lớp cha không sử dụng từ khóa extends mà dùng từ khóa implements.
Ví dụ:
Khai báo sau sẽ gặp lỗi khi class con không định nghĩa lại phương thức/thuộc tính của interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php //interface xe là class cha: interface xe{ public function banhxe(); } //class xe máy là class con: class xemay implements xe{ } //khởi tạo class xe máy: $xm = new xemay; //in ra bánh xe của xe máy: echo $xm->banhxe(); //kết quả sẽ xảy ra lỗi ?> |
Khai báo sau sẽ không xảy ra lỗi vì class con đã định nghĩa lại các phương thức có trong lớp interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php //interface xe là class cha: interface xe{ public function banhxe(); } //class xe máy là class con: class xemay implements xe{ //định nghĩa lại phương thức bánh xe của interface public function banhxe(){ return "Bánh xe của xe máy làm bằng bạch kim :v"; } } //khởi tạo class xe máy: $xm = new xemay; //in ra bánh xe của xe máy: echo $xm->banhxe(); //kết quả sẽ không có lỗi ?> |
Xem video hướng dẫn về kế thừa trong PHP: