Mẫu Singleton
Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 71 trên 91.
Mẫu Singleton (Singleton Pattern) là một mẫu thiết kế khởi tạo, đảm bảo một lớp chỉ có một instance trong suốt vòng đời ứng dụng. Mẫu này cũng cung cấp một điểm truy cập toàn cục đến instance đó.
Mẫu này hữu ích khi bạn cần chính xác một đối tượng điều phối các hoạt động trên toàn hệ thống, chẳng hạn như kết nối cơ sở dữ liệu, trình quản lý cấu hình hoặc trình ghi nhật ký. Tạo nhiều đối tượng như vậy sẽ gây lãng phí tài nguyên hoặc dẫn đến hành vi không nhất quán.
Sau đây là cách triển khai Singleton trong PHP:
<?php
class Database {
private static ?Database $instance = null;
private function __construct() {
// Hàm khởi tạo (constructor) private ngăn việc tạo instance trực tiếp
}
public static function getInstance(): Database {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function query(string $sql): string {
return "Executing: $sql";
}
}
$db1 = Database::getInstance();
$db2 = Database::getInstance();
echo $db1 === $db2 ? "Same instance" : "Different instances";
Đầu ra:
Same instanceMẫu này dựa trên ba thành phần chính: hàm khởi tạo riêng tư để ngăn việc gọi trực tiếp new, thuộc tính tĩnh lưu giữ một instance duy nhất và phương thức tĩnh tạo instance ở lần gọi đầu tiên rồi trả về instance đó trong những lần gọi tiếp theo.
Để Singleton thực sự không thể bị phá vỡ, bạn cũng nên ngăn việc sao chép và giải tuần tự hóa:
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
Thử thách
DễHãy xây dựng một trình quản lý cấu hình bằng mẫu Singleton (Singleton Pattern). Trong các ứng dụng thực tế, bạn thường muốn có một nguồn dữ liệu chuẩn duy nhất cho các thiết lập cấu hình: nếu có nhiều đối tượng cấu hình, hệ thống của bạn có thể hoạt động không nhất quán.
Bạn sẽ sắp xếp code trong hai tệp:
Config.php: Tạo một lớpConfigtriển khai mẫu Singleton. Trình quản lý cấu hình cần:- Lưu các thiết lập trong một thuộc tính mảng riêng tư
- Có hàm khởi tạo riêng tư, khởi tạo mảng thiết lập ở trạng thái rỗng
- Cung cấp phương thức tĩnh
getInstance()để trả về instance duy nhất - Ngăn việc sao chép bằng cách đặt
__clone()ở chế độ riêng tư - Có phương thức
set(string $key, string $value): voidđể lưu một thiết lập - Có phương thức
get(string $key): ?stringđể trả về giá trị của một khóa, hoặcnullnếu khóa đó không tồn tại - Có phương thức
getAll(): arrayđể trả về tất cả thiết lập
main.php: Thêm tệp Config. Bạn sẽ nhận hai đầu vào: một khóa và một giá trị.Lấy instance Config và đặt một thiết lập mặc định với khóa
"app_name"và giá trị"MyApp".Lấy tham chiếu thứ hai đến instance Config (gọi lại
getInstance()) rồi dùng tham chiếu đó để đặt một thiết lập khác bằng khóa và giá trị từ đầu vào.Cuối cùng, hãy xác minh Singleton hoạt động chính xác:
- In ra
"Same instance: true"hoặc"Same instance: false"tùy thuộc vào việc cả hai tham chiếu có trỏ đến cùng một đối tượng hay không (dùng===để so sánh) - In ra
"Settings count: [count]"để hiển thị tổng số thiết lập đã lưu (dùngcount()trên kết quả củagetAll()) - In ra
"App name: [value]"để hiển thị thiết lập app_name được lấy thông qua tham chiếu thứ hai
- In ra
Thử thách này minh họa lợi ích cốt lõi của mẫu Singleton: dù bạn gọi getInstance() bao nhiêu lần, bạn vẫn luôn nhận được cùng một đối tượng, nhờ đó mọi phần trong ứng dụng đều dùng chung trạng thái cấu hình.
Tự làm thử
<?php
require_once 'Config.php';
// Đọc đầu vào
$key = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Lấy instance của Config và đặt "app_name" thành "MyApp"
// TODO: Gọi lại getInstance() để lấy tham chiếu thứ hai đến Config
// TODO: Dùng tham chiếu thứ hai để đặt giá trị cài đặt bằng $key và $value từ đầu vào
// TODO: Kiểm tra Singleton có hoạt động không:
// - In ra "Same instance: true" hoặc "Same instance: false" dựa trên phép so sánh ===
// - In ra "Settings count: [count]" để hiển thị tổng số cài đặt
// - In ra "App name: [value]" để hiển thị app_name lấy qua tham chiếu thứ hai
?>Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa $thisPhương thứcThuộc tínhHàm khởi tạo (__construct)Hàm hủy (__destruct)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnTừ khóa parent::Ghi đè phương thứcTừ khóa finalLớp trừu tượngÔn tập: hệ thống phân cấp nhân viên7Đóng gói
Công khai, được bảo vệ, riêng tưTìm hiểu sâu về bộ điều chỉnh quyền truy cậpGetter và setterẨn thông tinRút gọn hàm khởi tạo (8.0)Ôn tập: hệ thống hồ sơ học sinh2Không gian tên và tự động nạp
Giới thiệu về không gian tênTừ khóa useChuẩn tự động nạp PSR-4Trình tự động nạp của ComposerÔn tập: dự án có tổ chức5Giao diện và hợp đồng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnGiao diện và lớp trừu tượngGợi ý kiểu với giao diệnÔn tập: Máy tính hình học8Phương thức ma thuật
Giới thiệu về phương thức ma thuật__toString và __debugInfo__get, __set, __isset, __unset__call và __callStatic__clone và sao chép đối tượng__serialize và __unserializeÔn tập: Bộ sưu tập tùy chỉnh3Thuộc tính của lớp
Thuộc tính instance và staticHằng số trong lớpPhương thức và thuộc tính staticThuộc tính private và protectedThuộc tính chỉ đọc (PHP 8.1)Ôn tập: Trình quản lý tài khoản ngân hàng6Đa hình
Xem lại việc ghi đè phương thứcĐa hình qua giao diệnGợi ý kiểu và kiểu hợpLiên kết tĩnh muộnÔn tập: bộ xử lý thanh toánTự luyện tập: Trình biên dịch PHP online