Inheritance is one of the foundations of Object-Oriented Programming (OOP) in PHP. It allows you to create new classes based on existing ones, reuse code, extend functionality, and organize application architecture. It builds directly on what you already know about classes and objects and about properties and methods.
This lesson explains:
- What inheritance is and why it’s used.
- How to use extends and parent::.
- How to override methods and work with constructors in a class hierarchy.
- Best practices, common mistakes, and practical PHP examples.
Basics of Inheritance in PHP
What is inheritance?
- Inheritance allows creating a child class (subclass) that inherits the features and behaviors of a base class (superclass).
- In PHP, we use the keyword extends to indicate that one class inherits from another.
- A child class can:
- use public and protected properties and methods of the base class,
- override methods (change their behavior),
- add its own properties and methods.
Visibility and inheritance
- public - accessible everywhere (and inherited).
- protected - accessible in the class and subclasses (inherited).
- private - accessible only in the same class (not accessible in child classes, cannot be overridden directly).
These three keywords are the subject of the next lesson, on encapsulation with public, private, and protected - here we only need the inheritance angle.
parent:: - when and why?
-
parent:: is the scope resolution operator that allows you to call:
- a method from the base class (
parent::method()), - the base class constructor (
parent::__construct()), - static methods, properties, and constants (
parent::CONSTANT,parent::staticMethod()).
- a method from the base class (
- Works only inside the child class definition.
PHP Code Examples
1) Simple inheritance with extends
class Vehicle
{
public string $brand;
public function drive(): void
{
echo "Vehicle is moving\n";
}
}
class Car extends Vehicle
{
public int $doors = 4;
public function stop(): void
{
echo "Car is braking\n";
}
}
$car = new Car();
$car->brand = "Toyota"; // inherited property
$car->drive(); // inherited method
$car->stop(); // child class method
2) Overriding methods and using parent::
class Vehicle
{
public function drive(): void
{
echo "Vehicle drives slowly\n";
}
}
class Motorcycle extends Vehicle
{
public function drive(): void
{
parent::drive(); // call parent logic
echo "Motorcycle accelerates fast\n";
}
}
$m = new Motorcycle();
$m->drive();
// Output:
// Vehicle drives slowly
// Motorcycle accelerates fast
3) Constructor inheritance: parent::__construct()
class User
{
protected string $email;
public function __construct(string $email)
{
$this->email = $email;
}
}
class Admin extends User
{
private array $permissions;
public function __construct(string $email, array $permissions = [])
{
parent::__construct($email); // call parent constructor
$this->permissions = $permissions;
}
}
$admin = new Admin("admin@example.com", ["USERS_READ", "USERS_WRITE"]);
4) private vs protected in inheritance
class Account
{
private float $privateBalance = 0.0; // not inherited
protected float $protectedBalance = 0.0; // inherited
protected function increaseBalance(float $amount): void
{
$this->protectedBalance += $amount;
}
}
class PremiumAccount extends Account
{
public function deposit(float $amount): void
{
// $this->privateBalance += $amount; // ERROR: private not accessible
$this->increaseBalance($amount); // OK: protected accessible
}
}
5) final - blocking inheritance and overriding
final class Singleton {}
// class Child extends Singleton {} // ERROR: cannot inherit from final class
class Service
{
final public function connect(): void { echo "Connecting...\n"; }
}
class SpecialService extends Service
{
// public function connect(): void {} // ERROR: cannot override final method
}
6) parent:: with static elements
class Config
{
public const VERSION = '1.0';
protected static string $mode = 'prod';
public static function info(): string
{
return "Version: " . self::VERSION . ", mode: " . static::$mode;
}
}
class DevConfig extends Config
{
protected static string $mode = 'dev';
public static function info(): string
{
$base = parent::info();
return $base . " (overridden in Dev)";
}
}
echo DevConfig::info();
// Version: 1.0, mode: dev (overridden in Dev)
7) Method signatures and compatibility (PHP 8+)
class Repository
{
public function find(int $id): ?stdClass
{
return (object)['id' => $id];
}
}
class UserRepository extends Repository
{
public function find(int $id): ?stdClass
{
return parent::find($id);
}
}
8) self:: vs parent:: vs static::
- self:: - refers to the current class (ignores later overrides).
- parent:: - refers to the immediate parent class.
- static:: - uses late static binding (important in static polymorphism).
Both class constants and the self vs static distinction and polymorphism get their own lessons later in this chapter - for now, just remember the three keywords exist.
Best Practices and Common Mistakes
Best Practices
- Prefer composition over inheritance when “has-a” fits better than “is-a”.
- Use inheritance only when a child is truly a special case of a parent.
- Use proper visibility:
- private for internal implementation details,
- protected to allow extension,
- Limit public to stable APIs.
- Always call
parent::__construct()if the parent requires initialization. - When overriding, call
parent::method()if you want to extend rather than replace logic. - Document and type all methods.
- Use final for classes/methods that should not be extended.
- Test base and child classes to maintain consistent behavior (Liskov Substitution Principle).
Common Mistakes
- Forgetting
parent::__construct()when required. - Trying to access private parent members from child.
- Overriding with incompatible signatures.
- Using
parent::outside class body. - Confusing
self::andparent::. - Overly deep inheritance hierarchies.
- Overusing inheritance where composition is better.
Summary
- Inheritance lets you create subclasses from base classes, reusing and extending logic.
- extends keyword declares inheritance.
- parent:: calls base class methods, constructor, or static elements.
- Visibility matters: public/protected are inherited, private is not.
- Use
parent::__construct()andparent::method()to reuse parent logic. - Apply best practices: limit hierarchy depth, use composition when appropriate, type and document.
Mini Quiz
- Which keyword makes class A inherit from class B? ➡️
extends - What does
parent::__construct()do in a child class? ➡️ Calls the parent’s constructor. - Which visibility is accessible in subclasses? ➡️ protected and public.
- When to use
parent::method()? ➡️ When overriding but also needing parent logic. - What does
finalmean for a method? ➡️ Cannot be overridden. - Can you use
parent::outside a class? ➡️ No.
Now you know the rules of inheritance in PHP with extends and parent::. Practice with simple hierarchies to strengthen your OOP skills.