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.
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:
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).
parent:: – when and why?
- parent:: is the scope resolution operator that allows you to call:
parent::method()
),
* the base class constructor (parent::__construct()
),
* static methods, properties, and constants (parent::CONSTANT
, parent::staticMethod()
).
- 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).
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:
- 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?
- Which visibility is accessible in subclasses?
- When to use
parent::method()
?
- What does
final
mean for a method?
- Can you use
parent::
outside a class?
Now you know the rules of inheritance in PHP with
extends
and parent::
. Practice with simple hierarchies to strengthen your OOP skills.