Sau khi nắm vững Constructor và Destructor, bước tiếp theo là học Tính kế thừa (Inheritance) – một trong 4 trụ cột của OOP. Inheritance cho phép class con kế thừa properties và methods từ class cha, giúp tái sử dụng code hiệu quả và tránh lặp lại. Đây là nền tảng để xây dựng hệ thống phân cấp class chuyên nghiệp.
1. Inheritance là gì?
Inheritance (Tính kế thừa) là cơ chế cho phép một class (class con) kế thừa toàn bộ properties và methods từ class khác (class cha). Class con có thể sử dụng, mở rộng hoặc ghi đè (override) những gì được kế thừa.
1.1. Vấn đề khi không có Inheritance
<?php
// ❌ Lặp lại code - khó bảo trì
class Dog {
public $name;
public $age;
public function eat() {
echo "$this->name đang ăn";
}
public function sleep() {
echo "$this->name đang ngủ";
}
}
class Cat {
public $name;
public $age;
public function eat() {
echo "$this->name đang ăn"; // Lặp lại!
}
public function sleep() {
echo "$this->name đang ngủ"; // Lặp lại!
}
}
class Bird {
public $name;
public $age;
public function eat() {
echo "$this->name đang ăn"; // Lặp lại!
}
public function sleep() {
echo "$this->name đang ngủ"; // Lặp lại!
}
}
?>1.2. Giải pháp: Dùng Inheritance
<?php
// ✅ Class cha - chứa code chung
class Animal {
public $name;
public $age;
public function eat() {
echo "$this->name đang ăn";
}
public function sleep() {
echo "$this->name đang ngủ";
}
}
// ✅ Class con - kế thừa từ Animal
class Dog extends Animal {
public function bark() {
echo "$this->name đang sủa: Gâu gâu!";
}
}
class Cat extends Animal {
public function meow() {
echo "$this->name đang kêu: Meo meo!";
}
}
class Bird extends Animal {
public function fly() {
echo "$this->name đang bay";
}
}
// Sử dụng
$dog = new Dog();
$dog->name = "Buddy";
$dog->eat(); // Từ Animal (kế thừa)
$dog->sleep(); // Từ Animal (kế thừa)
$dog->bark(); // Từ Dog (riêng)
?>2. Cú pháp Inheritance
<?php
// Class cha (Parent/Base/Super class)
class ParentClass {
public $property1;
public function method1() {
// Code
}
}
// Class con (Child/Derived/Sub class)
class ChildClass extends ParentClass {
public $property2; // Thêm property mới
public function method2() { // Thêm method mới
// Code
}
}
$child = new ChildClass();
$child->property1; // Từ ParentClass (kế thừa)
$child->property2; // Từ ChildClass (riêng)
$child->method1(); // Từ ParentClass (kế thừa)
$child->method2(); // Từ ChildClass (riêng)
?>Thuật ngữ:
extends– Từ khóa kế thừa- Parent Class (Base/Super) – Class cha
- Child Class (Derived/Sub) – Class con
- PHP chỉ hỗ trợ đơn kế thừa (1 class chỉ extends 1 class)
3. Ví dụ Inheritance cơ bản
3.1. Kế thừa Properties và Methods
<?php
class Person {
public $name;
public $age;
public function introduce() {
echo "Tôi là $this->name, $this->age tuổi";
}
public function walk() {
echo "$this->name đang đi bộ";
}
}
class Student extends Person {
public $studentId;
public $gpa;
public function study() {
echo "$this->name đang học bài";
}
}
// Sử dụng
$student = new Student();
$student->name = "Nguyễn Văn A"; // Từ Person
$student->age = 20; // Từ Person
$student->studentId = "SV001"; // Từ Student
$student->gpa = 3.5; // Từ Student
$student->introduce(); // Từ Person: Tôi là Nguyễn Văn A, 20 tuổi
$student->walk(); // Từ Person: Nguyễn Văn A đang đi bộ
$student->study(); // Từ Student: Nguyễn Văn A đang học bài
?>3.2. Kế thừa Constructor
<?php
class Vehicle {
public $brand;
public $color;
public function __construct($brand, $color) {
$this->brand = $brand;
$this->color = $color;
echo "Vehicle được khởi tạo
";
}
public function start() {
echo "Xe $this->brand đang khởi động";
}
}
class Car extends Vehicle {
public $seats;
public function __construct($brand, $color, $seats) {
// Gọi constructor của parent
parent::__construct($brand, $color);
$this->seats = $seats;
echo "Car được khởi tạo
";
}
public function displayInfo() {
echo "Xe {$this->brand} màu {$this->color}, {$this->seats} chỗ ngồi";
}
}
$car = new Car("Toyota", "Đỏ", 5);
// In:
// Vehicle được khởi tạo
// Car được khởi tạo
$car->displayInfo(); // Xe Toyota màu Đỏ, 5 chỗ ngồi
$car->start(); // Xe Toyota đang khởi động
?>💡 Lưu ý: Nếu child class có constructor riêng, nó sẽ ghi đè constructor của parent. Dùng
parent::__construct()để gọi constructor của parent.
4. Từ khóa parent
Từ khóa parent dùng để truy cập properties và methods của class cha từ class con.
<?php
class Employee {
protected $salary = 10000000;
public function calculateBonus() {
return $this->salary * 0.1;
}
public function displayInfo() {
echo "Lương: " . number_format($this->salary) . " VNĐ
";
}
}
class Manager extends Employee {
protected $teamSize;
public function __construct($teamSize) {
$this->teamSize = $teamSize;
$this->salary = 20000000; // Ghi đè salary
}
// Override method
public function calculateBonus() {
// Lấy bonus cơ bản từ parent
$baseBonus = parent::calculateBonus();
// Thêm bonus theo team size
$teamBonus = $this->teamSize * 500000;
return $baseBonus + $teamBonus;
}
public function displayInfo() {
// Gọi method của parent
parent::displayInfo();
// Thêm thông tin riêng
echo "Quản lý team: {$this->teamSize} người
";
echo "Bonus: " . number_format($this->calculateBonus()) . " VNĐ
";
}
}
$manager = new Manager(10);
$manager->displayInfo();
// In:
// Lương: 20,000,000 VNĐ
// Quản lý team: 10 người
// Bonus: 7,000,000 VNĐ (2tr base + 5tr team)
?>5. Override Methods (Ghi đè phương thức)
Override là khi class con định nghĩa lại method đã có ở class cha với cùng tên và tham số.
<?php
class Shape {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function getArea() {
return 0; // Method mặc định
}
public function display() {
echo "Hình: {$this->name}
";
echo "Diện tích: " . $this->getArea() . "
";
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($width, $height) {
parent::__construct("Hình chữ nhật");
$this->width = $width;
$this->height = $height;
}
// Override getArea()
public function getArea() {
return $this->width * $this->height;
}
}
class Circle extends Shape {
private $radius;
public function __construct($radius) {
parent::__construct("Hình tròn");
$this->radius = $radius;
}
// Override getArea()
public function getArea() {
return pi() * $this->radius * $this->radius;
}
}
$rect = new Rectangle(5, 10);
$rect->display();
// In:
// Hình: Hình chữ nhật
// Diện tích: 50
$circle = new Circle(7);
$circle->display();
// In:
// Hình: Hình tròn
// Diện tích: 153.93804002589
?>5.1. Quy tắc Override
- ✅ Method con phải có cùng tên với method cha
- ✅ Method con phải có cùng số tham số (hoặc tương thích)
- ✅ Method con có thể thay đổi logic bên trong
- ✅ Method con phải có access modifier rộng hơn hoặc bằng cha (protected → public OK, public → protected ❌)
- ✅ Có thể gọi method cha bằng
parent::methodName()
6. Access Modifiers trong Inheritance
| Modifier | Trong class cha | Trong class con | Bên ngoài |
|---|---|---|---|
public | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ❌ |
private | ✅ | ❌ | ❌ |
<?php
class ParentClass {
public $publicVar = "Public";
protected $protectedVar = "Protected";
private $privateVar = "Private";
public function showVars() {
echo $this->publicVar . "
"; // OK
echo $this->protectedVar . "
"; // OK
echo $this->privateVar . "
"; // OK
}
}
class ChildClass extends ParentClass {
public function accessParentVars() {
echo $this->publicVar . "
"; // ✅ OK
echo $this->protectedVar . "
"; // ✅ OK
// echo $this->privateVar; // ❌ Lỗi - private không kế thừa
}
}
$child = new ChildClass();
echo $child->publicVar; // ✅ OK
// echo $child->protectedVar; // ❌ Lỗi - protected chỉ trong class
// echo $child->privateVar; // ❌ Lỗi - private chỉ trong class cha
?>💡 Best Practice: Dùng
protectedcho properties/methods muốn class con kế thừa nhưng ẩn khỏi bên ngoài.
7. Ví dụ thực tế
7.1. Hệ thống User
<?php
class User {
protected $id;
protected $name;
protected $email;
protected $created_at;
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
$this->created_at = date("Y-m-d H:i:s");
}
public function getName() {
return $this->name;
}
public function getEmail() {
return $this->email;
}
public function displayInfo() {
echo "Name: {$this->name}
";
echo "Email: {$this->email}
";
}
}
class Admin extends User {
private $permissions = [];
public function __construct($name, $email, $permissions = []) {
parent::__construct($name, $email);
$this->permissions = $permissions;
}
public function addPermission($permission) {
$this->permissions[] = $permission;
}
public function hasPermission($permission) {
return in_array($permission, $this->permissions);
}
public function displayInfo() {
parent::displayInfo(); // Hiển thị info cơ bản
echo "Role: Admin
";
echo "Permissions: " . implode(", ", $this->permissions) . "
";
}
}
class Customer extends User {
private $orders = [];
private $loyaltyPoints = 0;
public function addOrder($order) {
$this->orders[] = $order;
$this->loyaltyPoints += 10;
}
public function getOrderCount() {
return count($this->orders);
}
public function displayInfo() {
parent::displayInfo();
echo "Role: Customer
";
echo "Orders: {$this->getOrderCount()}
";
echo "Loyalty Points: {$this->loyaltyPoints}
";
}
}
// Sử dụng
$admin = new Admin("Admin User", "admin@site.com", ["create_user", "delete_user"]);
$admin->displayInfo();
echo "
";
$customer = new Customer("Customer User", "customer@email.com");
$customer->addOrder("Order #1");
$customer->addOrder("Order #2");
$customer->displayInfo();
?>7.2. Hệ thống Payment
<?php
abstract class Payment {
protected $amount;
protected $currency;
protected $status = "pending";
public function __construct($amount, $currency = "VND") {
$this->amount = $amount;
$this->currency = $currency;
}
public function getAmount() {
return $this->amount;
}
public function getStatus() {
return $this->status;
}
// Method chung
protected function validate() {
if ($this->amount <= 0) {
throw new Exception("Số tiền phải > 0");
}
return true;
}
// Method abstract - bắt buộc override
abstract public function process();
}
class CreditCardPayment extends Payment {
private $cardNumber;
private $cvv;
public function __construct($amount, $cardNumber, $cvv) {
parent::__construct($amount);
$this->cardNumber = $cardNumber;
$this->cvv = $cvv;
}
public function process() {
$this->validate();
// Logic xử lý thẻ
echo "Đang xử lý thanh toán thẻ tín dụng...
";
echo "Số thẻ: " . substr($this->cardNumber, -4) . "
";
echo "Số tiền: " . number_format($this->amount) . " {$this->currency}
";
$this->status = "completed";
return true;
}
}
class MomoPayment extends Payment {
private $phoneNumber;
public function __construct($amount, $phoneNumber) {
parent::__construct($amount);
$this->phoneNumber = $phoneNumber;
}
public function process() {
$this->validate();
// Logic xử lý Momo
echo "Đang xử lý thanh toán Momo...
";
echo "SĐT: {$this->phoneNumber}
";
echo "Số tiền: " . number_format($this->amount) . " {$this->currency}
";
$this->status = "completed";
return true;
}
}
class BankTransferPayment extends Payment {
private $accountNumber;
private $bankCode;
public function __construct($amount, $accountNumber, $bankCode) {
parent::__construct($amount);
$this->accountNumber = $accountNumber;
$this->bankCode = $bankCode;
}
public function process() {
$this->validate();
// Logic chuyển khoản
echo "Đang xử lý chuyển khoản ngân hàng...
";
echo "Ngân hàng: {$this->bankCode}
";
echo "STK: {$this->accountNumber}
";
echo "Số tiền: " . number_format($this->amount) . " {$this->currency}
";
$this->status = "pending_confirmation";
return true;
}
}
// Sử dụng
$payments = [
new CreditCardPayment(1000000, "1234567890123456", "123"),
new MomoPayment(500000, "0912345678"),
new BankTransferPayment(2000000, "0123456789", "VCB")
];
foreach ($payments as $payment) {
$payment->process();
echo "Trạng thái: " . $payment->getStatus() . "
";
}
?>7.3. Hệ thống Database Connection
<?php
class DatabaseConnection {
protected $host;
protected $username;
protected $password;
protected $conn;
public function __construct($host, $username, $password) {
$this->host = $host;
$this->username = $username;
$this->password = $password;
}
public function connect() {
// Override trong child class
}
public function disconnect() {
$this->conn = null;
}
public function isConnected() {
return $this->conn !== null;
}
}
class MySQLConnection extends DatabaseConnection {
private $database;
public function __construct($host, $username, $password, $database) {
parent::__construct($host, $username, $password);
$this->database = $database;
}
public function connect() {
try {
$dsn = "mysql:host={$this->host};dbname={$this->database};charset=utf8mb4";
$this->conn = new PDO($dsn, $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "✓ Kết nối MySQL thành công
";
} catch (PDOException $e) {
echo "✗ Lỗi MySQL: " . $e->getMessage() . "
";
}
}
public function query($sql) {
if (!$this->isConnected()) {
$this->connect();
}
return $this->conn->query($sql);
}
}
class PostgreSQLConnection extends DatabaseConnection {
private $database;
private $port;
public function __construct($host, $username, $password, $database, $port = 5432) {
parent::__construct($host, $username, $password);
$this->database = $database;
$this->port = $port;
}
public function connect() {
try {
$dsn = "pgsql:host={$this->host};port={$this->port};dbname={$this->database}";
$this->conn = new PDO($dsn, $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "✓ Kết nối PostgreSQL thành công
";
} catch (PDOException $e) {
echo "✗ Lỗi PostgreSQL: " . $e->getMessage() . "
";
}
}
public function query($sql) {
if (!$this->isConnected()) {
$this->connect();
}
return $this->conn->query($sql);
}
}
// Sử dụng
$mysql = new MySQLConnection("localhost", "root", "", "test_db");
$mysql->connect();
$pgsql = new PostgreSQLConnection("localhost", "postgres", "password", "mydb");
$pgsql->connect();
?>8. Kiểm tra Inheritance
<?php
class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }
$dog = new Dog();
// Kiểm tra object thuộc class nào
var_dump($dog instanceof Dog); // true
var_dump($dog instanceof Animal); // true (vì Dog extends Animal)
var_dump($dog instanceof Cat); // false
// Kiểm tra class con của class cha
var_dump(is_subclass_of($dog, 'Animal')); // true
var_dump(is_subclass_of('Dog', 'Animal')); // true (dùng tên class)
// Lấy class cha
echo get_parent_class($dog); // Animal
echo get_parent_class('Dog'); // Animal
?>9. Multi-level Inheritance
PHP hỗ trợ kế thừa nhiều cấp (A → B → C).
<?php
class LivingThing {
public function breathe() {
echo "Đang thở
";
}
}
class Animal extends LivingThing {
public function eat() {
echo "Đang ăn
";
}
}
class Mammal extends Animal {
public function giveBirth() {
echo "Sinh con
";
}
}
class Dog extends Mammal {
public function bark() {
echo "Sủa: Gâu gâu!
";
}
}
$dog = new Dog();
$dog->breathe(); // Từ LivingThing
$dog->eat(); // Từ Animal
$dog->giveBirth(); // Từ Mammal
$dog->bark(); // Từ Dog
// Kiểm tra
var_dump($dog instanceof Dog); // true
var_dump($dog instanceof Mammal); // true
var_dump($dog instanceof Animal); // true
var_dump($dog instanceof LivingThing); // true
?>10. Best Practices
10.1. Khi nào dùng Inheritance
✅ NÊN dùng khi:
- Có quan hệ “IS-A” (Dog IS-A Animal, Car IS-A Vehicle)
- Muốn tái sử dụng code từ class cha
- Các class có chung properties/methods cơ bản
- Cần phân cấp rõ ràng (User → Admin/Customer)
❌ KHÔNG nên dùng khi:
- Quan hệ “HAS-A” (Car HAS-A Engine → dùng Composition)
- Chỉ để tái sử dụng 1-2 methods (dùng Trait)
- Class con không có quan hệ logic với cha
- Tạo cây kế thừa quá sâu (> 3-4 cấp)
10.2. Inheritance vs Composition
<?php
// ❌ SAI - Dùng Inheritance cho HAS-A
class Car extends Engine { // Car không phải là Engine!
// ...
}
// ✅ ĐÚNG - Dùng Composition cho HAS-A
class Car {
private $engine; // Car có một Engine
public function __construct(Engine $engine) {
$this->engine = $engine;
}
public function start() {
$this->engine->start();
}
}
class Engine {
public function start() {
echo "Engine khởi động";
}
}
$engine = new Engine();
$car = new Car($engine);
$car->start();
?>Tóm tắt
Qua bài này bạn đã nắm được:
- ✅ Inheritance: Class con kế thừa properties/methods từ class cha
- ✅ Từ khóa extends:
class Child extends Parent - ✅ Từ khóa parent: Truy cập properties/methods của class cha
- ✅ Override: Class con ghi đè method của class cha
- ✅ Constructor: Dùng
parent::__construct()trong child constructor - ✅ Access Modifiers: public (mọi nơi), protected (class + con), private (chỉ class cha)
- ✅ Multi-level: A → B → C (kế thừa nhiều cấp)
- ✅ Single Inheritance: PHP chỉ extends 1 class (không hỗ trợ đa kế thừa)
Bài tiếp theo, bạn sẽ học về Encapsulation (Tính đóng gói) – bảo vệ dữ liệu với Getter/Setter.
🎯 Bài tập thực hành
- Bài 1: Tạo class
BankAccount(balance, deposit, withdraw). Tạo classSavingsAccountextends BankAccount thêm interestRate và calculateInterest(). - Bài 2: Tạo class
Product(name, price, getInfo()). TạoDigitalProduct(downloadLink) vàPhysicalProduct(weight, shippingCost) extends Product. - Bài 3: Tạo class
Employee(name, baseSalary, calculateSalary()). TạoFullTimeEmployee(bonus) vàPartTimeEmployee(hourlyRate, hoursWorked) extends Employee, override calculateSalary().
Gợi ý Bài 1:
<?php
class BankAccount {
protected $balance;
public function __construct($initialBalance = 0) {
$this->balance = $initialBalance;
}
public function deposit($amount) {
if ($amount > 0) {
$this->balance += $amount;
return true;
}
return false;
}
public function withdraw($amount) {
if ($amount > 0 && $amount <= $this->balance) {
$this->balance -= $amount;
return true;
}
return false;
}
public function getBalance() {
return $this->balance;
}
}
class SavingsAccount extends BankAccount {
private $interestRate;
public function __construct($initialBalance, $interestRate) {
parent::__construct($initialBalance);
$this->interestRate = $interestRate;
}
public function calculateInterest() {
return $this->balance * ($this->interestRate / 100);
}
public function applyInterest() {
$interest = $this->calculateInterest();
$this->balance += $interest;
return $interest;
}
}
$savings = new SavingsAccount(10000000, 5); // 10tr, lãi 5%
echo "Số dư: " . number_format($savings->getBalance()) . "
";
echo "Lãi: " . number_format($savings->calculateInterest()) . "
";
$savings->applyInterest();
echo "Số dư sau lãi: " . number_format($savings->getBalance());
?>