Menu
CoddyTech

Sử dụng nhiều đặc tính

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

Một trait rất hữu ích, nhưng sức mạnh thực sự đến từ việc kết hợp nhiều trait trong cùng một lớp. PHP cho phép bạn thêm bao nhiêu trait tùy ý, giúp lớp của bạn có khả năng từ nhiều nguồn cùng lúc.

Để sử dụng nhiều trait, chỉ cần liệt kê chúng, ngăn cách bằng dấu phẩy, sau từ khóa use:

<?php
trait Timestampable {
    public function getTimestamp(): string {
        return date('Y-m-d H:i:s');
    }
}

trait Identifiable {
    private string $id;
    
    public function generateId(): void {
        $this->id = uniqid('id_');
    }
    
    public function getId(): string {
        return $this->id;
    }
}

class Post {
    use Timestampable, Identifiable;
    
    public function __construct(public string $title) {
        $this->generateId();
    }
}

$post = new Post("Hello World");
echo $post->getId() . " - " . $post->getTimestamp();

Đầu ra:

id_6789abc123 - 2024-01-15 10:30:00

Lớp Post hiện có các phương thức từ cả hai trait. Mỗi trait bổ sung chức năng riêng: Timestampable cung cấp các phương thức liên quan đến thời gian, còn Identifiable xử lý các ID duy nhất. Cách làm này giúp mỗi trait tập trung vào một trách nhiệm, khiến code của bạn có tính mô-đun và dễ tái sử dụng hơn.

Điều gì xảy ra khi hai trait có các phương thức trùng tên? Chúng ta sẽ tìm hiểu tình huống xung đột này trong bài học tiếp theo.

challenge icon

Thử thách

Dễ

Hãy xây dựng hệ thống quản lý sản phẩm kết hợp nhiều trait để sản phẩm có cả chức năng định giá và quản lý hàng tồn kho. Mỗi trait sẽ đảm nhiệm một trách nhiệm riêng, còn lớp sản phẩm sẽ có chức năng từ cả hai trait.

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

  • Priceable.php: Tạo trait có tên Priceable để xử lý chức năng định giá. Trait cần có:
    • Thuộc tính riêng tư $price (số thực)
    • Phương thức setPrice(float $price) để lưu giá
    • Phương thức getPrice() để trả về giá
    • Phương thức getFormattedPrice() để trả về giá theo định dạng "$[price]" với 2 chữ số thập phân
  • Stockable.php: Tạo trait có tên Stockable để quản lý hàng tồn kho. Trait cần có:
    • Thuộc tính riêng tư $stock (số nguyên)
    • Phương thức setStock(int $quantity) để lưu số lượng hàng tồn kho
    • Phương thức getStock() để trả về lượng hàng tồn kho hiện tại
    • Phương thức isInStock() trả về true nếu lượng hàng tồn kho lớn hơn 0, nếu không thì trả về false
  • main.php: Nạp cả hai tệp trait và tạo lớp Product sử dụng cả hai trait Priceable và Stockable. Dùng tính năng khai báo thuộc tính trong hàm khởi tạo để định nghĩa thuộc tính công khai $name. Hàm khởi tạo cũng cần nhận giá và số lượng hàng tồn kho, rồi dùng các phương thức của trait để thiết lập chúng.

    Bạn sẽ nhận ba đầu vào: tên sản phẩm, giá và số lượng hàng tồn kho. Tạo sản phẩm với các giá trị này và in ra bốn dòng:

    • Tên sản phẩm
    • Giá đã định dạng (dùng getFormattedPrice())
    • Số lượng hàng tồn kho
    • "Available" nếu còn hàng, hoặc "Out of stock" nếu hết hàng

Ví dụ này cho thấy cách nhiều trait phối hợp với nhau. Lớp Product có chức năng định giá từ một trait và chức năng quản lý hàng tồn kho từ trait còn lại. Mỗi trách nhiệm được tách biệt rõ ràng, đồng thời kết hợp lại thành một sản phẩm đầy đủ chức năng.

Tự làm thử

<?php
require_once 'Priceable.php';
require_once 'Stockable.php';

// TODO: Tạo lớp (class) Product sử dụng cả hai trait Priceable và Stockable
// Dùng constructor promotion cho thuộc tính (property) public $name
// Hàm khởi tạo (constructor) cần nhận name, price và stock, rồi dùng các phương thức (method) của trait để đặt price và stock

class Product {
    // TODO: Sử dụng các trait ở đây

    // TODO: Triển khai hàm khởi tạo bằng constructor promotion cho $name
    // và dùng các phương thức của trait để đặt price và stock
}

// Đọc đầu vào (input)
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$stock = intval(trim(fgets(STDIN)));

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

// TODO: In ra tên sản phẩm
// TODO: In ra giá đã định dạng bằng getFormattedPrice()
// TODO: In ra số lượng tồn kho
// TODO: In ra "Available" nếu còn hàng, hoặc "Out of stock" nếu hết hà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