PHP Inheritance

Yo Yogesh.M Updated 17 Oct 2026
6 min read ·Lesson 67 of 109
In this post

What Is Inheritance? In simple terms: Inheritance lets one class build on another. A child class automatically receives the properties and methods of its parent class, and can add new ones or change h

What Is Inheritance?

In simple terms: Inheritance lets one class build on another. A child class automatically receives the properties and methods of its parent class, and can add new ones or change how inherited ones behave. A savings account is a bank account with an extra feature (interest); instead of rewriting everything a bank account does, the savings account class extends the account class.

Technically: A class declared with extends ParentClass inherits all public and protected members of the parent. The child can add members, override inherited methods, and call the parent's versions with parent::. PHP supports single inheritance: a class can extend only one parent, but inheritance chains (A → B → C) are possible. Objects of a child class are also instances of the parent class.

          Account
   (owner, balance, deposit, withdraw)
          ▲                ▲
          │                │
   SavingsAccount     CurrentAccount
   (+ interest)       (+ overdraft limit)

Syntax

class ChildClass extends ParentClass
{
    // additional or overridden members
}

A Complete Example: Bank Accounts

<?php
class Account
{
    protected float $balance;

    public function __construct(protected string $owner, float $openingBalance = 0)
    {
        $this->balance = $openingBalance;
    }

    public function deposit(float $amount): void
    {
        if ($amount <= 0) {
            throw new InvalidArgumentException('Deposit must be positive.');
        }
        $this->balance += $amount;
    }

    public function withdraw(float $amount): void
    {
        if (!$this->canWithdraw($amount)) {
            throw new RuntimeException("Insufficient funds for {$this->owner}.");
        }
        $this->balance -= $amount;
    }

    public function describe(): string
    {
        return sprintf('%s | %s | ₹%s', $this->type(), $this->owner, number_format($this->balance, 2));
    }

    protected function canWithdraw(float $amount): bool
    {
        return $amount <= $this->balance;
    }

    protected function type(): string
    {
        return 'Account';
    }
}

class SavingsAccount extends Account
{
    public function __construct(string $owner, float $openingBalance, private float $ratePercent)
    {
        parent::__construct($owner, $openingBalance);
    }

    public function addInterest(): void
    {
        $this->balance += round($this->balance * $this->ratePercent / 100, 2);
    }

    protected function type(): string
    {
        return 'Savings';
    }
}

class CurrentAccount extends Account
{
    public function __construct(string $owner, float $openingBalance, private float $overdraftLimit)
    {
        parent::__construct($owner, $openingBalance);
    }

    protected function canWithdraw(float $amount): bool
    {
        return $amount <= $this->balance + $this->overdraftLimit;
    }

    protected function type(): string
    {
        return 'Current';
    }
}

$savings = new SavingsAccount('Asha', 10000, 4.0);
$savings->addInterest();

$current = new CurrentAccount('GoCourse Pvt Ltd', 2000, 5000);
$current->withdraw(6000);

echo $savings->describe() . "\n";
echo $current->describe() . "\n";

foreach ([[$savings, 20000], [$current, 2000]] as [$account, $amount]) {
    try {
        $account->withdraw($amount);
    } catch (RuntimeException $e) {
        echo "Error: " . $e->getMessage() . "\n";
    }
}

Output

Savings | Asha | ₹10,400.00
Current | GoCourse Pvt Ltd | ₹-4,000.00
Error: Insufficient funds for Asha.
Error: Insufficient funds for GoCourse Pvt Ltd.

How It Works

  1. Inherited behavior: deposit(), withdraw(), and describe() are written once in Account; both child classes use them without repeating code.
  2. Added behavior: SavingsAccount adds addInterest(), which only savings accounts have.
  3. Overridden behavior: CurrentAccount overrides canWithdraw() to allow an overdraft. The inherited withdraw() calls $this->canWithdraw(), and because $this is a CurrentAccount, the child's version runs. This is how a parent method can be customized without being rewritten.
  4. Protected members: balance, owner, canWithdraw(), and type() are protected, so child classes can use and override them, while outside code cannot.
  5. Parent constructor: each child constructor calls parent::__construct() to let Account initialize its own properties.

The current account was allowed to go to −₹4,000 (within its ₹5,000 overdraft), but the next withdrawal of ₹2,000 would exceed the limit.


Calling the Parent Constructor

If a child class defines its own constructor, the parent's constructor is not called automatically. Forgetting parent::__construct() leaves the parent's properties uninitialized:

<?php
class Base
{
    protected string $createdBy;

    public function __construct(string $user)
    {
        $this->createdBy = $user;
    }
}

class Draft extends Base
{
    public function __construct(private string $title)
    {
        // parent::__construct() is missing
    }

    public function info(): string
    {
        return "{$this->title} by {$this->createdBy}";
    }
}

try {
    echo (new Draft('Intro to PHP'))->info();
} catch (Error $e) {
    echo $e->getMessage() . "\n";
}

Output

Typed property Base::$createdBy must not be accessed before initialization

If a child class does not define a constructor at all, the parent's constructor is inherited and used automatically.


Objects of a Child Class Are Also Parent Objects

<?php
class Account {}
class SavingsAccount extends Account {}

$savings = new SavingsAccount();

var_dump($savings instanceof SavingsAccount);
var_dump($savings instanceof Account);
var_dump(get_parent_class($savings));

function printStatement(Account $account): void
{
    echo "Statement for " . get_class($account) . "\n";
}

printStatement($savings);

Output

bool(true)
bool(true)
string(7) "Account"
Statement for SavingsAccount

A function that accepts an Account also accepts any subclass. This is the basis of polymorphism: code written for the parent type works with every child type (see Polymorphism).


What Is and Is Not Inherited

MemberInherited?Notes
Public and protected properties and methodsYesCan be used and overridden
Private properties and methodsNot accessibleThey exist in the object, but only the parent's own code can use them
ConstantsYesAccessible via self::, static::, or ChildClass::
Static membersYesSee PHP Static Properties
ConstructorYes, if the child has noneOtherwise, call parent::__construct() explicitly

Inheritance vs Composition

Inheritance models an "is-a" relationship: a savings account is an account. It is often misused for "has-a" or "uses-a" relationships, which are better modeled by composition — one object holding another:

// Inheritance misused: an order is not a logger
class Order extends Logger { /* ... */ }

// Composition: an order service uses a logger
class OrderService
{
    public function __construct(private Logger $logger) {}
}

Why Prefer Composition in Many Cases

InheritanceComposition
Fixed at compile timeCollaborators can be swapped (also in tests)
Child classes depend on parent internals (protected members)Objects interact only through public interfaces
Only one parent classAny number of collaborators
Changes in the parent can break childrenChanges stay local

A common guideline is "favor composition over inheritance": use inheritance for genuine specializations sharing a common core, and composition for everything else. Interfaces (see PHP Interfaces) and traits (see PHP Traits) cover many cases where inheritance would otherwise be tempting.


Common Mistakes

Forgetting parent::__construct()

Effect: Parent properties remain uninitialized.

Fix: Call the parent constructor from the child constructor.

Using Inheritance to Share Utility Code

Effect: Unrelated classes inherit from a "BaseHelper", creating rigid hierarchies.

Fix: Use composition or traits.

Deep Inheritance Chains

Effect: Behavior is spread over many levels and hard to follow.

Fix: Keep hierarchies shallow (one or two levels is typical).

Accessing Private Parent Members From Children

Effect: The properties appear undefined in the child class.

Fix: Make them protected, or use parent methods.

Overriding Methods With Incompatible Signatures

Effect: Fatal errors (see Method Overriding).

Fix: Keep parameter and return types compatible with the parent method.


Best Practices

  • Use inheritance only for true "is-a" relationships with shared behavior.
  • Keep shared logic in the parent and specialized logic in child classes.
  • Design explicit extension points with protected methods.
  • Always call parent::__construct() when overriding the constructor.
  • Prefer composition and interfaces when classes merely need to use or provide behavior.

Official reference: https://www.php.net/manual/en/language.oop5.inheritance.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about PHP Inheritance and get answers drawn from it.

Signed-in readers only.