Inheritance and Interfaces
Inheritance lets a class (a subclass) reuse and extend the properties and methods of another class (its parent) using the extends keyword, modeling an 'is-a' relationship such as a SavingsAccount being a kind of Account. PHP supports only single inheritance — a class may extend exactly one parent class — but a class can implement any number of interfaces via implements, which is how PHP achieves multiple-contract polymorphism without the ambiguity of multiple class inheritance. An interface declares a set of public method signatures (and optionally constants) that any implementing class must provide, without specifying how those methods work.
Cricket analogy: A SavingsAccount extending Account is like a T20 match extending the general rules of cricket, adding its own powerplay restrictions on top of the base laws of the game, an 'is-a' relationship of match format to sport.
Extending Classes and Overriding Methods
A subclass inherits all non-private members of its parent and may override any inherited method by redeclaring it with the same signature (or a compatible, covariant one). Inside an overriding method, parent::methodName() calls the parent's original implementation, which is the standard way to extend rather than fully replace inherited behavior — for example, calling parent::__construct() to run the parent's initialization logic before adding subclass-specific setup.
Cricket analogy: Calling parent::methodName() when overriding is like a new captain running the standard warm-up drill their predecessor established before adding their own personal fielding-practice twist on top, rather than scrapping the routine entirely.
class Account
{
public function __construct(protected float $balance = 0.0) {}
public function deposit(float $amount): void
{
$this->balance += $amount;
}
public function describe(): string
{
return sprintf('Balance: %.2f', $this->balance);
}
}
class SavingsAccount extends Account
{
public function __construct(float $balance, private readonly float $interestRate)
{
parent::__construct($balance);
}
public function describe(): string
{
return parent::describe() . sprintf(' (rate %.1f%%)', $this->interestRate * 100);
}
}Defining and Implementing Interfaces
An interface is declared with the interface keyword and lists method signatures with no bodies (except default constant values it may declare). A class opts into an interface's contract with implements, and must define every method the interface declares, with a matching (or covariant) signature, or PHP raises a fatal error. Since PHP 8.1, interfaces themselves can also declare enum-friendly constants and be composed via extends between interfaces (an interface can extend multiple other interfaces, unlike classes).
Cricket analogy: An interface listing method signatures with no bodies is like the laws of cricket specifying that a bowler must deliver the ball within the crease, without dictating exact bowling action, and since PHP 8.1 an interface can extend multiple other interfaces, like ICC playing conditions building on several base rule sets.
interface Payable
{
public function amountDue(): float;
}
interface Printable
{
public function toReceipt(): string;
}
class Invoice implements Payable, Printable
{
public function __construct(private float $total) {}
public function amountDue(): float
{
return $this->total;
}
public function toReceipt(): string
{
return sprintf('Invoice total: %.2f', $this->total);
}
}
function charge(Payable $item): void
{
echo $item->amountDue();
}Why Prefer Interfaces to Inheritance in Many Designs
Because PHP only allows one parent class, deep inheritance hierarchies can quickly become rigid and force awkward compromises when a class genuinely needs behavior from two unrelated lineages. Interfaces avoid this by letting a class fulfill many independent contracts (a User might implement both Authenticatable and Notifiable), while composition (holding another object as a collaborator rather than inheriting from it) is often preferred over deep inheritance chains for sharing implementation, keeping each class focused and the overall design easier to change.
Cricket analogy: Deep inheritance chains are like trying to make a player be both a specialist opener and a death-over finisher through one rigid batting lineage; interfaces let a User implement both Authenticatable and Notifiable the way a player can simply hold two independent skills, opener and finisher, as separate contracts rather than forcing one twisted lineage.
A widely used design guideline is 'program to an interface, not an implementation': functions and methods should accept parameters typed as an interface (like Payable) rather than a concrete class, so any object fulfilling that contract can be passed in, including test doubles, without the function needing to know or care about the concrete class.
Overriding a method with an incompatible signature — for example narrowing a parameter type in a way the parent didn't allow, or changing visibility to be more restrictive than the parent declared — violates PHP's Liskov-substitution-oriented type variance rules and will raise a fatal error at declaration time, not just a warning.
extendscreates single inheritance between two classes;implementslets a class fulfill any number of interface contracts.- Overriding methods can call the parent's original implementation via
parent::methodName(). - Interfaces declare method signatures (and optionally constants) with no implementation bodies; implementing classes must satisfy every declared method.
- Unlike classes, interfaces can extend multiple other interfaces at once.
- Overriding method signatures must remain compatible (covariant) with the parent/interface declaration or PHP raises a fatal error.
- Favor typing against interfaces and using composition over deep inheritance chains for flexible, decoupled design.
Practice what you learned
1. How many classes can a single PHP class directly extend?
2. What is the purpose of calling parent::__construct() inside a subclass constructor?
3. What must a class do to satisfy an interface it implements?
4. Which of the following is true about interfaces extending other interfaces?
5. Why is typing a function parameter as an interface (e.g. Payable $item) generally preferred over a concrete class type?
Was this page helpful?
You May Also Like
Classes and Objects
Explore PHP's object-oriented foundations: declaring classes, constructing objects, typed properties, visibility, and constructor promotion.
Abstract Classes and Polymorphism
Abstract classes define a partial implementation and a contract that subclasses must complete, enabling polymorphic code that treats different concrete types uniformly.
Traits in PHP
Traits let you share method implementations across unrelated classes without using inheritance, solving PHP's single-inheritance limitation for horizontal code reuse.
Magic Methods
Magic methods are special, double-underscore-prefixed hooks PHP invokes automatically for events like object construction, property access, and string conversion.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics