Hiểu sâu về `parent::__construct()` trong Lập trình Hướng đối tượng PHP (OOP)
1. Phân tích cú pháp (The What)
Đoạn code trên bao gồm 2 thành phần chính:
public function __construct(): Đây là Magic Method khởi tạo (Constructor) của class con hiện tại. Nó sẽ tự động được chạy ngay khi bạn khởi tạo một object mới bằng từ khóanew.parent::__construct(): Lệnh này dùng để gọi ngược lên hàm khởi tạo của class cha (class mà class hiện tại đangextends).
2. Tại sao lại cần gọi parent::__construct()? (The Why)
Trong một số ngôn ngữ lập trình khác (như Java hay C#), khi class con được khởi tạo, hàm khởi tạo không tham số của class cha sẽ tự động được gọi ngầm.
Nhưng PHP thì KHÔNG làm thế.
Trong PHP, nếu class con khai báo một hàm __construct() của riêng nó, hàm này sẽ ghi đè (override) hoàn toàn hàm khởi tạo của class cha. Điều này có nghĩa là mọi logic setup, gán giá trị mặc định, hay kết nối database nằm trong __construct của class cha sẽ bị bỏ qua và không bao giờ được chạy.
Ví dụ minh họa:
class DatabaseConnection {
protected $connection;
public function __construct() {
// Logic kết nối DB rất quan trọng
$this->connection = "Connected to MySQL";
echo "1. Đã chạy constructor của Cha.\n";
}
}
class UserRepository extends DatabaseConnection {
protected $table;
public function __construct() {
// PHẢI CÓ dòng này để class cha thiết lập $connection
parent::__construct();
$this->table = 'users';
echo "2. Đã chạy constructor của Con.\n";
}
}
$repo = new UserRepository();
// Kết quả in ra:
// 1. Đã chạy constructor của Cha.
// 2. Đã chạy constructor của Con.
Hệ lụy: Nếu trong
UserRepositorybạn quên mất dòngparent::__construct();, biến$this->connectionsẽ bịnullvà toàn bộ logic gọi DB phía sau sẽ crash ngay lập tức.
3. Khi nào đoạn code trên trở thành "Code rác" (Anti-pattern)?
Nếu class con chỉ viết đúng đoạn code gọi parent mà không làm thêm bất cứ logic nào khác, thì đây được xem là code thừa (redundant code).
class ChildClass extends ParentClass {
// ❌ ĐOẠN CODE NÀY LÀ THỪA THÃI VÀ NÊN XÓA BỎ
public function __construct() {
parent::__construct();
}
}
Lý do:
PHP có một cơ chế fallback. Nếu class con không khai báo hàm __construct(), PHP sẽ tự động tìm và chạy hàm __construct() của class cha (nếu cha có khai báo).
Do đó, bạn chỉ nên khai báo __construct() trong class con khi thực sự cần:
- Truyền thêm tham số mới (Dependency Injection).
- Gán giá trị cho các thuộc tính riêng của class con.
- Chạy một logic đặc thù nào đó trước hoặc sau khi class cha khởi tạo.
4. Ứng dụng thực tế trong các Framework (ví dụ: Laravel)
Nếu làm việc với các hệ thống backend phức tạp, bạn sẽ rất hay gặp pattern này trong Base Controller hoặc Base Repository.
Ví dụ trong Controller của Laravel:
class BaseController extends Controller {
public function __construct() {
// Define middleware chung cho toàn bộ Base
$this->middleware('auth');
}
}
class UserController extends BaseController {
public function __construct() {
// Kế thừa middleware 'auth' từ BaseController
parent::__construct();
// Khai báo thêm middleware riêng cho UserController
$this->middleware('log.user.action');
}
}
💡 Tóm lại
- Dùng
parent::__construct()khi class con có logic khởi tạo riêng nhưng vẫn muốn giữ lại logic khởi tạo của class cha. - Xóa luôn hàm
__construct()ở class con nếu bên trong nó không có dòng code nào khác ngoài lệnh gọiparent. Điều này giúp code clean và dễ bảo trì hơn.
All rights reserved