Menu
CoddyTech

__serialize và __unserialize

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 49 trên 91.

Khi cần chuyển đổi một đối tượng thành chuỗi để lưu trữ hoặc truyền đi, PHP sử dụng tuần tự hóa (serialization). Các phương thức ma thuật __serialize() và __unserialize() cho phép bạn kiểm soát chính xác dữ liệu nào được lưu và cách khôi phục dữ liệu đó.

Phương thức __serialize() trả về một mảng dữ liệu cần được tuần tự hóa, còn __unserialize() nhận mảng đó và dựng lại đối tượng:

<?php
class Session {
    public function __construct(
        private string $userId,
        private array $data,
        private int $createdAt
    ) {}
    
    public function __serialize(): array {
        return [
            'userId' => $this->userId,
            'data' => $this->data
        ];
    }
    
    public function __unserialize(array $data): void {
        $this->userId = $data['userId'];
        $this->data = $data['data'];
        $this->createdAt = time();
    }
    
    public function getCreatedAt(): int {
        return $this->createdAt;
    }
}

$session = new Session("user123", ["theme" => "dark"], time());
$serialized = serialize($session);

$restored = unserialize($serialized);
echo "Created at: " . $restored->getCreatedAt();

Hãy chú ý rằng createdAt bị loại khỏi quá trình tuần tự hóa (serialization) và có dấu thời gian mới khi giải tuần tự hóa. Cách này hữu ích khi cần loại trừ dữ liệu nhạy cảm, giá trị tạm thời hoặc tài nguyên không thể tuần tự hóa như kết nối cơ sở dữ liệu.

Các phương thức này đã thay thế các phương thức cũ hơn __sleep() và __wakeup() trong PHP 7.4, mang đến cách tiếp cận gọn gàng hơn, cho phép bạn làm việc trực tiếp với các mảng dữ liệu thay vì tên thuộc tính.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống lưu vào bộ nhớ đệm hồ sơ người dùng để minh họa cách __serialize() và __unserialize() cho bạn quyền kiểm soát dữ liệu nào được lưu và cách khôi phục dữ liệu đó.

Bạn sẽ sắp xếp code trong hai tệp:

  • UserProfile.php: Tạo lớp UserProfile đại diện cho hồ sơ người dùng có khả năng lưu vào bộ nhớ đệm. Dùng cách khai báo thuộc tính ngay trong hàm khởi tạo để định nghĩa các thuộc tính riêng tư $userId (chuỗi), $username (chuỗi), $email (chuỗi) và $accessToken (chuỗi). Thêm thuộc tính riêng tư $cachedAt để lưu thời điểm hồ sơ được lưu vào bộ nhớ đệm (ban đầu đặt thành "not cached" trong hàm khởi tạo). Lớp của bạn cần có:
    • __serialize(): Trả về một mảng chỉ chứa userId, username và email. accessToken chứa thông tin nhạy cảm và không bao giờ được tuần tự hóa. Dấu thời gian cachedAt sẽ được tạo lại khi khôi phục.
    • __unserialize(): Khôi phục userId, username và email từ mảng dữ liệu. Đặt accessToken thành "expired" (vì token không nên được lưu lại).
    • getInfo(): Trả về một chuỗi theo định dạng: "[username] ([email]) - Token: [accessToken] - Cached: [cachedAt]"
  • main.php: Nạp tệp UserProfile. Bạn sẽ nhận bốn đầu vào: ID người dùng, tên người dùng, email và access token. Tạo một instance UserProfile với các giá trị này. In ra ba dòng:
    • Thông tin hồ sơ ban đầu (trước khi tuần tự hóa)
    • Tuần tự hóa hồ sơ bằng serialize(), sau đó giải tuần tự hóa bằng unserialize() để tạo hồ sơ đã khôi phục. In thông tin hồ sơ đã khôi phục.
    • In ra "Token preserved: yes" hoặc "Token preserved: no" tùy vào việc token của hồ sơ đã khôi phục có khớp với token ban đầu hay không (gợi ý: chúng không nên khớp vì token hết hạn khi khôi phục)

Mẫu này rất cần thiết để lưu dữ liệu người dùng vào bộ nhớ đệm một cách an toàn. Bạn muốn lưu thông tin hồ sơ nhưng không bao giờ lưu lại thông tin xác thực nhạy cảm như access token. Khi khôi phục hồ sơ từ bộ nhớ đệm, token được đánh dấu là hết hạn, buộc ứng dụng phải lấy token mới.

Tự làm thử

<?php

require_once 'UserProfile.php';

// Đọc dữ liệu đầu vào
$userId = trim(fgets(STDIN));
$username = trim(fgets(STDIN));
$email = trim(fgets(STDIN));
$accessToken = trim(fgets(STDIN));

// TODO: Tạo một instance UserProfile bằng các giá trị đầu vào

// TODO: In ra thông tin của hồ sơ gốc (trước khi tuần tự hóa)

// TODO: Tuần tự hóa hồ sơ, rồi giải tuần tự hóa để tạo hồ sơ được khôi phục

// TODO: In ra thông tin của hồ sơ được khôi phục

// TODO: In ra "Token preserved: yes" hoặc "Token preserved: no"
// tùy vào việc token của hồ sơ được khôi phục có khớp với token gốc hay không

?>
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