Menu
CoddyTech

__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.99

Theo 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: 0

Phươ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.

challenge icon

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ớp Document đạ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ùng date('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à $createdAt cầ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ột Document vớ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

?>
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch PHP online