Menu
Coddy logo textTech

Использование нескольких трейтов

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 52 из 91.

Один трейт полезен, но настоящая мощь проявляется тогда, когда вы объединяете несколько трейтов в одном классе. PHP позволяет подключать столько трейтов, сколько вам нужно, наделяя ваш класс возможностями из нескольких источников одновременно.

Чтобы использовать несколько трейтов, просто перечислите их через запятую после ключевого слова 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();

Вывод:

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

Класс Post теперь имеет методы из обоих трейтов. Каждый трейт вносит свою функциональность — Timestampable предоставляет методы, связанные со временем, в то время как Identifiable обрабатывает уникальные идентификаторы. Этот подход позволяет каждому трейту сосредоточиться на одной ответственности, делая ваш код более модульным и переиспользуемым.

Что происходит, когда два трейта имеют методы с одинаковыми именами? Это конфликтная ситуация, которую мы изучим в следующем уроке.

challenge icon

Задание

Легко

Давайте создадим систему управления продуктами, которая объединяет несколько трейтов, чтобы наделить продукты возможностями ценообразования и управления запасами. Каждый трейт будет отвечать за одну задачу, а ваш класс продукта получит функциональность от обоих.

Вы организуете свой код в трех файлах:

  • Priceable.php — Создайте трейт с именем Priceable, который обрабатывает функциональность ценообразования. Трейт должен иметь:
    • Приватное свойство $price (float)
    • Метод setPrice(float $price), который сохраняет цену
    • Метод getPrice(), который возвращает цену
    • Метод getFormattedPrice(), который возвращает цену, отформатированную как "$[price]" с 2 знаками после запятой
  • Stockable.php — Создайте трейт с именем Stockable, который управляет запасами. Трейт должен иметь:
    • Приватное свойство $stock (integer)
    • Метод setStock(int $quantity), который сохраняет количество товара на складе
    • Метод getStock(), который возвращает текущий запас
    • Метод isInStock(), который возвращает true, если запас больше 0, и false в противном случае
  • main.php — Подключите оба файла трейтов и создайте класс Product, который использует трейты Priceable и Stockable. Используйте продвижение свойств в конструкторе (constructor promotion) для определения публичного свойства $name. Конструктор также должен принимать цену и количество товара, используя методы трейтов для их установки.

    Вы получите три входных значения: название продукта, цену и количество на складе. Создайте продукт с этими значениями и выведите четыре строки:

    • Название продукта
    • Отформатированную цену (используя getFormattedPrice())
    • Количество на складе
    • "Available", если товар есть в наличии, или "Out of stock", если нет

Это демонстрирует, как несколько трейтов работают вместе — ваш класс Product получает возможности ценообразования от одного трейта и управление запасами от другого, сохраняя каждую задачу четко разделенной и объединяя их в полнофункциональный продукт.

Шпаргалка

Чтобы использовать несколько трейтов в классе, перечислите их через запятую после ключевого слова 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();
// Output: id_6789abc123 - 2024-01-15 10:30:00

Каждый трейт привносит в класс свою функциональность. Такой подход позволяет каждому трейту сосредоточиться на одной задаче, делая код более модульным и пригодным для повторного использования.

Попробуйте сами

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

// TODO: Создайте класс Product, который использует трейты Priceable и Stockable
// Используйте продвижение свойств в конструкторе (constructor promotion) для публичного свойства $name
// Конструктор должен принимать name, price и stock, и использовать методы трейтов для установки цены и количества на складе

class Product {
    // TODO: Используйте трейты здесь

    // TODO: Реализуйте конструктор с продвижением свойств для $name
    // и установите цену и количество на складе, используя методы трейтов
}

// Чтение входных данных
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$stock = intval(trim(fgets(STDIN)));

// TODO: Создайте экземпляр Product с входными значениями

// TODO: Выведите название продукта
// TODO: Выведите отформатированную цену, используя getFormattedPrice()
// TODO: Выведите количество на складе
// TODO: Выведите "Available", если товар есть в наличии, или "Out of stock", если нет
?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование