OOP Bài 9: Default Constructor và Parameterized Constructor
1. Default Constructor (Hàm tạo mặc định)
- Khái niệm: Là Constructor không nhận vào bất kỳ tham số (parameter) nào từ bên ngoài.
- Đặc điểm thực chiến:
- Trạng thái tĩnh: Tất cả các Object sinh ra từ Default Constructor ban đầu sẽ có chung một trạng thái y hệt nhau. Dữ liệu bên trong thường được gán cứng (hard-code) hoặc để trống (
null,0,false). - Sự ưu ái của ORM: Nếu bạn làm việc với các ORM (Object-Relational Mapping), đôi khi hệ thống bắt buộc Class (Entity) phải có Default Constructor. Tại sao? Vì khi query DB (
SELECT * FROM users), ORM sẽ tạo ra một Object rỗng trước bằng Default Constructor, sau đó mới dùng cơ chế Reflection (phản chiếu) để âm thầm nhồi data từ các cột SQL vào các thuộc tính của Object đó.
- Trạng thái tĩnh: Tất cả các Object sinh ra từ Default Constructor ban đầu sẽ có chung một trạng thái y hệt nhau. Dữ liệu bên trong thường được gán cứng (hard-code) hoặc để trống (
class GuestSession {
private $role;
private $createdAt;
// Default Constructor: Không nhận tham số
public function __construct() {
$this->role = 'GUEST'; // Gán cứng mặc định
$this->createdAt = time();
}
}
// Khởi tạo không cần truyền dữ liệu
$session1 = new GuestSession();
$session2 = new GuestSession(); // session1 và session2 ban đầu có trạng thái giống hệt nhau
2. Parameterized Constructor (Hàm tạo có tham số)
- Khái niệm: Là Constructor yêu cầu phải truyền dữ liệu (tham số) vào ngay tại thời điểm gọi từ khóa
new. - Tại sao nó là xương sống của OOP hiện đại?
- Bảo vệ tính toàn vẹn (Data Integrity): Ngăn chặn việc tạo ra các Object "khuyết tật". Ví dụ: Một đối tượng
Transaction(Giao dịch AFC) không thể tồn tại nếu không cóticketIdvàamount. Parameterized Constructor ép buộc lập trình viên phải cung cấp đủ những dữ liệu sống còn này thì Object mới được phép ra đời. - Dependency Injection (DI): Đây là cách chuẩn mực để bơm các dependency (như Database Connection, Logger, Message Broker) từ bên ngoài vào trong Class, giúp code lỏng lẻo (loose coupling) và dễ viết Unit Test.
- Bảo vệ tính toàn vẹn (Data Integrity): Ngăn chặn việc tạo ra các Object "khuyết tật". Ví dụ: Một đối tượng
class AfcTransaction {
private $ticketId;
private $amount;
private $timestamp;
// Parameterized Constructor: Bắt buộc truyền tham số
public function __construct($ticketId, $amount) {
if ($amount <= 0) {
throw new Exception("Số tiền giao dịch không hợp lệ!");
}
$this->ticketId = $ticketId;
$this->amount = $amount;
$this->timestamp = time();
}
}
// KHÔNG THỂ gọi: new AfcTransaction(); => Hệ thống sẽ báo lỗi ngay lập tức
// BẮT BUỘC GỌI:
$tx = new AfcTransaction("TICK_888", 15000); // Object ra đời với trạng thái an toàn
3. Vấn đề nạp chồng Constructor (Constructor Overloading)
Ở các ngôn ngữ như C++ hay Java, bạn hoàn toàn có thể khai báo cả hai loại Constructor này trong cùng một Class (gọi là Overloading). Tùy vào cách gọi new mà trình biên dịch sẽ tự biết chạy hàm nào.
Nhưng trong PHP, một Class chỉ được phép có duy nhất một hàm __construct(). Vậy làm sao để xử lý khi ta vừa muốn tạo Object rỗng, vừa muốn tạo Object có tham số?
Giải pháp thực chiến (Design Pattern): Static Factory Methods
Thay vì cố gắng nhồi nhét logic vào __construct(), các Senior Developer sẽ biến Constructor thành private (đóng cửa) và cung cấp các hàm tĩnh (static) mang tính mô tả rõ ràng để khởi tạo Object.
class Ticket {
private $type;
private $price;
// Đóng cửa Constructor, chỉ dùng nội bộ
private function __construct() {}
// Factory Method 1: Tương đương Default Constructor
public static function createFreePass() {
$ticket = new self();
$ticket->type = 'FREE_PASS';
$ticket->price = 0;
return $ticket;
}
// Factory Method 2: Tương đương Parameterized Constructor
public static function createStandardTicket($price) {
$ticket = new self();
$ticket->type = 'STANDARD';
$ticket->price = $price;
return $ticket;
}
}
// Luồng code gọi (rất rõ ràng theo chuẩn DDD - Domain Driven Design):
$vipTicket = Ticket::createFreePass();
$normalTicket = Ticket::createStandardTicket(15000);
Lợi ích: Cách viết này giúp mã nguồn Backend trở nên cực kỳ trong sáng, dễ đọc và thể hiện rõ ý đồ của luồng nghiệp vụ.
All rights reserved