Menu
CoddyTech

Getter và setter

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

Bây giờ bạn đã hiểu về các từ bổ nghĩa quyền truy cập, làm thế nào để tương tác an toàn với các thuộc tính private từ bên ngoài lớp? Câu trả lời là phương thức truy xuất và thiết lập (getters and setters), tức các phương thức public giúp kiểm soát quyền truy cập vào dữ liệu private.

Getter lấy giá trị của một thuộc tính, còn setter thay đổi giá trị đó. Mẫu này cho phép bạn thêm quy tắc xác thực hoặc logic khi truy cập hay thay đổi dữ liệu:

<?php
class User {
    private string $email;
    private int $age;
    
    public function getEmail(): string {
        return $this->email;
    }
    
    public function setEmail(string $email): void {
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->email = $email;
        }
    }
    
    public function getAge(): int {
        return $this->age;
    }
    
    public function setAge(int $age): void {
        if ($age >= 0 && $age <= 150) {
            $this->age = $age;
        }
    }
}

$user = new User();
$user->setEmail("john@example.com");
$user->setAge(25);

echo $user->getEmail() . "\n";
echo $user->getAge();

Đầu ra:

john@example.com
25

Phương thức setter kiểm tra định dạng email và đảm bảo tuổi hợp lý trước khi lưu các giá trị. Nếu không có setter, bất kỳ ai cũng có thể gán trực tiếp dữ liệu không hợp lệ. Bạn cũng có thể tạo thuộc tính chỉ đọc bằng cách chỉ cung cấp getter, hoặc thuộc tính chỉ ghi bằng cách chỉ cung cấp setter.

Điểm chính: Getter và setter giúp bạn kiểm soát cách truy cập và chỉnh sửa dữ liệu riêng tư, cho phép kiểm tra tính hợp lệ, định dạng hoặc áp dụng logic tùy chỉnh.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống quản lý hàng tồn kho sản phẩm, sử dụng getter và setter để bảo vệ và xác thực dữ liệu sản phẩm. Bạn sẽ tạo một lớp Product để đảm bảo giá luôn dương và số lượng hàng tồn kho không bao giờ âm, qua đó minh họa cách setter có thể thực thi các quy tắc kinh doanh.

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

  • Product.php: Tạo một lớp Product có ba thuộc tính riêng tư: $name (chuỗi), $price (số thực) và $stock (số nguyên). Tạo getter và setter cho từng thuộc tính với các quy tắc xác thực sau:
    • setName() chỉ nên chấp nhận chuỗi không rỗng. Nếu chuỗi rỗng sau khi xóa khoảng trắng ở đầu và cuối, đừng cập nhật thuộc tính
    • setPrice() chỉ nên chấp nhận giá trị lớn hơn 0: từ chối giá bằng 0 hoặc giá âm
    • setStock() chỉ nên chấp nhận giá trị từ 0 trở lên: từ chối số lượng hàng tồn kho âm
    Mỗi getter chỉ cần trả về giá trị của thuộc tính tương ứng. Thêm một phương thức công khai getInfo() trả về "[name]: $[price] ([stock] in stock)", trong đó giá được định dạng với 2 chữ số thập phân.
  • main.php: Đưa tệp Product vào. Bạn sẽ nhận được bốn đầu vào: tên sản phẩm, giá, số lượng hàng tồn kho và giá mới để cập nhật. Tạo một đối tượng Product rồi dùng các setter để gán tên, giá ban đầu (đã chuyển đổi sang số thực) và số lượng hàng tồn kho (đã chuyển đổi sang số nguyên). In kết quả của getInfo(). Sau đó thử cập nhật giá bằng giá trị giá mới (đã chuyển đổi sang số thực) và in lại getInfo(). Cuối cùng, thử đặt số lượng hàng tồn kho thành -5 (một giá trị không hợp lệ) rồi in getInfo() thêm một lần nữa để xác nhận số lượng hàng tồn kho không thay đổi.

Các setter của bạn đóng vai trò như người gác cổng. Chúng xác thực dữ liệu đầu vào trước khi cho phép thay đổi các thuộc tính riêng tư. Khi nhận dữ liệu không hợp lệ, chẳng hạn như số lượng hàng tồn kho âm, setter chỉ cần bỏ qua dữ liệu đó và giữ nguyên giá trị hợp lệ hiện có. Đây chính là sức mạnh của tính đóng gói: đối tượng của bạn luôn duy trì tính toàn vẹn bất kể code bên ngoài cố làm gì.

Tự làm thử

<?php
require_once 'Product.php';

// Đọc các giá trị đầu vào
$name = trim(fgets(STDIN));
$price = trim(fgets(STDIN));
$stock = trim(fgets(STDIN));
$newPrice = trim(fgets(STDIN));

// TODO: Tạo một instance Product mới

// TODO: Dùng các phương thức setter để gán tên, giá và stock ban đầu, trong đó giá là số thực và stock là số nguyên

// TODO: In ra kết quả của getInfo()

// TODO: Cập nhật giá bằng newPrice (dưới dạng số thực), rồi in getInfo() lần nữa

// TODO: Thử đặt stock thành -5 (không hợp lệ), rồi in getInfo() để xác nhận stock không thay đổi

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