__clone và sao chép đối tượng
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 48 trên 91.
Khi gán một đối tượng cho biến khác trong PHP, bạn không tạo bản sao, cả hai biến đều trỏ đến cùng một đối tượng. Để tạo một bản sao độc lập thực sự, bạn cần dùng từ khóa clone:
<?php
class Product {
public function __construct(
public string $name,
public float $price
) {}
}
$original = new Product("Laptop", 999.99);
$copy = clone $original;
$copy->price = 899.99;
echo $original->price . " - " . $copy->price;
Đầu ra:
999.99 - 899.99Theo mặc định, PHP thực hiện bản sao nông - sao chép trực tiếp tất cả giá trị thuộc tính. Cách này hoạt động tốt với các giá trị vô hướng, nhưng các đối tượng bên trong đối tượng của bạn vẫn tham chiếu đến cùng một instance. Phương thức ma thuật __clone() cho phép bạn tùy chỉnh hành vi này:
<?php
class Order {
public function __construct(
public int $id,
public array $items = []
) {}
public function __clone(): void {
$this->id = 0;
$this->items = [];
}
}
$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;
echo "Original: " . $order1->id . ", Clone: " . $order2->id;
Đầu ra:
Original: 101, Clone: 0Phương thức __clone() được gọi trên đối tượng mới sau khi tạo bản sao nông. Đây là nơi bạn đặt lại ID, tạo bản sao mới của các đối tượng lồng nhau hoặc thực hiện mọi thao tác dọn dẹp cần thiết để bản sao thực sự độc lập.
Thử thách
DễHãy xây dựng một hệ thống quản lý phiên bản tài liệu để tìm hiểu cách thao tác clone tạo ra các bản sao độc lập và cách phương thức đặc biệt __clone() cho phép bạn tùy chỉnh điều xảy ra khi một đối tượng được clone.
Bạn sẽ sắp xếp code trong hai tệp:
Document.php: Tạo lớpDocumentđại diện cho một tài liệu có phiên bản. Dùng tính năng khai báo thuộc tính trong hàm khởi tạo để định nghĩa$title(chuỗi) và$content(chuỗi) ở phạm vi công khai, cùng với$version(số nguyên, mặc định là 1) ở phạm vi công khai. Thêm thuộc tính$createdAtở phạm vi riêng tư để lưu dấu thời gian hiện tại (dùngdate('Y-m-d H:i:s')trong hàm khởi tạo). Tài liệu của bạn cần có:getCreatedAt(): trả về dấu thời gian tạo__clone(): khi một tài liệu được clone, phiên bản cần tăng thêm 1 và$createdAtcần được đặt lại thành dấu thời gian hiện tại (bản clone là một phiên bản mới được tạo vào "now")
main.php: Nạp tệp Document. Bạn sẽ nhận ba đầu vào: tiêu đề, nội dung và một chuỗi nội dung mới cho phiên bản được clone. Tạo mộtDocumentvới tiêu đề và nội dung đó. Sau đó clone tài liệu để tạo phiên bản mới rồi cập nhật nội dung của bản clone thành chuỗi nội dung mới. In ra bốn dòng:- Phiên bản của tài liệu gốc
- Phiên bản của tài liệu được clone
- Nội dung của tài liệu gốc
- Nội dung của tài liệu được clone
Hệ thống này cho thấy __clone() cho phép bạn kiểm soát điều xảy ra trong quá trình clone. Tài liệu gốc giữ nguyên phiên bản và thời gian tạo, còn bản clone tự động trở thành phiên bản mới với dấu thời gian mới. Cách này rất phù hợp để theo dõi lịch sử tài liệu, trong đó mỗi bản clone đại diện cho một lần chỉnh sửa mới.
Tự làm thử
<?php
require_once 'Document.php';
// Đọc dữ liệu đầu vào
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));
// TODO: Tạo một Document với tiêu đề và nội dung
// TODO: Clone tài liệu để tạo phiên bản mới
// TODO: Cập nhật nội dung của bản clone thành chuỗi nội dung mới
// TODO: In ra bốn dòng:
// 1. Phiên bản của tài liệu gốc
// 2. Phiên bản của tài liệu đã clone
// 3. Nội dung của tài liệu gốc
// 4. Nội dung của tài liệu đã clone
?>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