The inheritance allows creating a class from another and reusing or specializing its behavior.
Imagine you are programming a video game. You have a Warrior, a Mage, and an Archer.
They all have things in common: they have a name, they have health points (HP), and they can move.
The novice (and painful) way:
You create three classes (Warrior, Mage, Archer) and copy and paste the code for $name, $hp, and move() into all three. If tomorrow you want to change how movement works, you have to edit three files. Bad.
The OOP way (Inheritance):
You create a base class called Character (the parent) with the common stuff. Then you have the other classes (the children) inherit from it.
The extends Keyword
We use extends to say “Class B is a specialized version of Class A”.
// Parent Class (Base)
class Character {
public function __construct(
public string $name,
protected int $hp = 100 // protected: children can access it
) {}
public function move(): void {
echo "{$this->name} is moving.\n";
}
}
// Child Class
// "The Warrior IS A Character"
class Warrior extends Character {
public function attack(): void {
echo "Sword slash!\n";
}
}When creating the instance, the following happens:
$guts = new Warrior("Guts");
// The Warrior has the move() method even though we didn't write it in him!
$guts->move(); // Output: Guts is moving.
$guts->attack(); // Output: Sword slash!The Warrior has inherited everything public and protected from Character.
Method Overriding
Sometimes, the child doesn’t want to do exactly the same as the parent. It wants to behave differently.
Imagine the Mage doesn’t walk, but levitates instead. We can override the move method in the child class.
class Mage extends Character {
// Override: We define the method with the SAME name
public function move(): void {
echo "{$this->name} magically teleports ✨.\n";
}
}
$gandalf = new Mage("Gandalf");
$gandalf->move(); // Output: Gandalf magically teleports ✨.PHP is smart: if you call move(), it looks first in the Child class. If it exists, it uses that. If not, it goes up to the Parent.
Accessing the Parent (parent::)
What if you don’t want to completely replace the parent, but only add something extra?
A classic case is the Constructor. The Warrior needs to initialize its $name (like any character) but also its $weapon (which is exclusive to him).
We use parent:: to call methods from the parent class.
class Warrior extends Character {
public function __construct(
string $name,
public string $weapon // New property
) {
// Call the parent constructor to set the name and hp
parent::__construct($name);
}
public function attack(): void {
echo "Attacks with {$this->weapon}\n";
}
}If you override the __construct in the child, PHP will not automatically call the parent’s constructor. It is your responsibility to call parent::__construct(...) if you need it.
The final Keyword (the party stops here)
Sometimes you create a class that is so perfect or critical that you don’t want anyone to modify it or inherit from it. To forbid inheritance, we use final.
Final Classes
Nobody can do extends from this.
final class SecuritySystem {
// ...
}
// class Hack extends SecuritySystem {} // ❌ FATAL ERRORMarking a class as final is reasonable when it is not part of an extension contract. It prevents accidental inheritance, although it doesn’t have to be the right choice for all classes.
Final Methods
You allow inheriting the class, but you forbid changing a specific method.
class Character {
// Children can change move(), but NEVER die()
final public function die(): void {
echo "Game Over.";
}
}