Traits vs Inheritance
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 55 of 91.
Now that you understand how traits work, let's clarify when to use traits versus inheritance. Both allow code reuse, but they serve different purposes and have distinct characteristics.
Inheritance establishes an "is-a" relationship. A Dog class extending Animal means a dog is an animal. The child class inherits the parent's identity and can be used anywhere the parent type is expected.
Traits provide a "has-a" capability. When a class uses a Loggable trait, it has logging functionality - but it doesn't become a logger. Traits add behavior without changing what the class fundamentally is.
<?php
// Inheritance: Dog IS an Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Dog HAS logging capability
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
Key differences to remember:
| Aspect | Inheritance | Traits |
|---|---|---|
| Relationship | is-a | has-a capability |
| Limit | Single parent only | Multiple traits allowed |
| Type checking | Works with instanceof | No type identity |
| Best for | Hierarchical relationships | Shared behaviors across unrelated classes |
Use inheritance when classes share a common identity. Use traits when unrelated classes need the same functionality without being part of the same family tree.
Challenge
EasyLet's build a vehicle system that demonstrates when to use inheritance versus traits. You'll create a hierarchy of vehicles that share a common identity through inheritance, while adding cross-cutting capabilities through traits.
You'll organize your code across four files:
Trackable.php— Create a trait calledTrackablethat provides GPS tracking capability. The trait should have:- A private property
$location(string) - A method
setLocation(string $location)that stores the current location - A method
getLocation()that returns"Location: [location]"
- A private property
Vehicle.php— Create a baseVehicleclass that establishes the "is-a" relationship. Include the trait file. Use constructor promotion to define a protected$brandproperty. Add a methoddescribe()that returns"Vehicle: [brand]". This class should use theTrackabletrait since all vehicles in our fleet will have GPS.Car.php— Create aCarclass that extendsVehicle. Include the Vehicle file. Use constructor promotion to accept the brand and a private$doors(integer) property. Call the parent constructor with the brand. Override thedescribe()method to return"Car: [brand] with [doors] doors".main.php— Include the Car file. You'll receive three inputs: a brand name, a number of doors, and a location string. Create aCarinstance, set its location, then print two lines:- The result of calling
describe() - The result of calling
getLocation()
- The result of calling
Notice how inheritance and traits work together here: Car is a Vehicle (inheritance establishes identity), while Vehicle has tracking capability (the trait adds behavior). You could use instanceof Vehicle to check if something is a vehicle, but there's no "Trackable" type to check against — that's the key difference between these two approaches.
Cheat sheet
Use inheritance for "is-a" relationships and traits for "has-a" capabilities.
Inheritance establishes identity - a child class is a type of parent class and can be used anywhere the parent type is expected.
Traits add behavior without changing class identity - a class has functionality but doesn't become that thing.
<?php
// Inheritance: Dog IS an Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Cat HAS logging capability
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
| Aspect | Inheritance | Traits |
|---|---|---|
| Relationship | is-a | has-a capability |
| Limit | Single parent only | Multiple traits allowed |
| Type checking | Works with instanceof | No type identity |
| Best for | Hierarchical relationships | Shared behaviors across unrelated classes |
Use inheritance for hierarchical relationships where classes share common identity. Use traits for shared behaviors across unrelated classes.
Try it yourself
<?php
// Main file - create and test the Car instance
// TODO: Include the Car.php file
// Read inputs
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));
// TODO: Create a Car instance with brand and doors
// TODO: Set the car's location
// TODO: Print the result of describe()
// TODO: Print the result of getLocation()
?>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