Using Multiple Traits
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 52 of 91.
A single trait is useful, but the real power comes when you combine multiple traits in one class. PHP lets you include as many traits as you need, giving your class capabilities from several sources at once.
To use multiple traits, simply list them separated by commas after the use keyword:
<?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:00The Post class now has methods from both traits. Each trait contributes its own functionality - Timestampable provides time-related methods while Identifiable handles unique IDs. This approach keeps each trait focused on a single responsibility, making your code more modular and reusable.
What happens when two traits have methods with the same name? That's a conflict situation we'll explore in the next lesson.
Challenge
EasyLet's build a product management system that combines multiple traits to give products both pricing and inventory capabilities. Each trait will handle a single responsibility, and your product class will gain functionality from both.
You'll organize your code across three files:
Priceable.php— Create a trait calledPriceablethat handles pricing functionality. The trait should have:- A private property
$price(float) - A method
setPrice(float $price)that stores the price - A method
getPrice()that returns the price - A method
getFormattedPrice()that returns the price formatted as"$[price]"with 2 decimal places
- A private property
Stockable.php— Create a trait calledStockablethat manages inventory. The trait should have:- A private property
$stock(integer) - A method
setStock(int $quantity)that stores the stock quantity - A method
getStock()that returns the current stock - A method
isInStock()that returnstrueif stock is greater than 0,falseotherwise
- A private property
main.php— Include both trait files and create aProductclass that uses bothPriceableandStockabletraits. Use constructor promotion to define a public$nameproperty. The constructor should also accept a price and stock quantity, using the trait methods to set them.You'll receive three inputs: a product name, a price, and a stock quantity. Create a product with these values and print four lines:
- The product name
- The formatted price (using
getFormattedPrice()) - The stock quantity
"Available"if in stock, or"Out of stock"if not
This demonstrates how multiple traits work together — your Product class gains pricing capabilities from one trait and inventory management from another, keeping each concern neatly separated while combining them into a fully-featured product.
Cheat sheet
To use multiple traits in a class, list them separated by commas after the use keyword:
<?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
Each trait contributes its own functionality to the class. This approach keeps each trait focused on a single responsibility, making code more modular and reusable.
Try it yourself
<?php
require_once 'Priceable.php';
require_once 'Stockable.php';
// TODO: Create a Product class that uses both Priceable and Stockable traits
// Use constructor promotion for the public $name property
// The constructor should accept name, price, and stock, and use trait methods to set price and stock
class Product {
// TODO: Use the traits here
// TODO: Implement constructor with constructor promotion for $name
// and set price and stock using trait methods
}
// Read input
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$stock = intval(trim(fgets(STDIN)));
// TODO: Create a Product instance with the input values
// TODO: Print the product name
// TODO: Print the formatted price using getFormattedPrice()
// TODO: Print the stock quantity
// TODO: Print "Available" if in stock, or "Out of stock" if not
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern