Inheritance — extends, method overriding, parent::
Concept
Inheritance lets a class extend another, inheriting all public and protected methods and properties. PHP supports single inheritance only — a class can only extend one parent. (Multiple interface implementation is available, and traits provide horizontal code reuse.)
extends: The child class gains all public/protected members of the parent. Private members are inherited in memory but inaccessible from the child. The child can add new methods/properties and override inherited ones.
Method overriding: Redefining a parent method in the child replaces it. The override must be compatible — in PHP 8, the signature must be a subtype (covariant return type, contravariant parameter types). Calling parent::methodName() invokes the parent implementation from within the override.
Constructor inheritance: Constructors are NOT automatically called — if the child defines __construct, it must explicitly call parent::__construct() if needed. If the child doesn't define __construct, the parent's is inherited.
When inheritance is appropriate: When there is a genuine "is-a" relationship (a Dog IS an Animal). When you want to provide a base implementation with hooks for subclasses to customize (Template Method pattern). When you need to add behavior to existing classes you own.
When inheritance is abused: Using it purely for code reuse without an "is-a" relationship. Prefer composition — a UserService that HAS a Logger is cleaner than a UserService that IS a Logger.
Code Example
<?php
declare(strict_types=1);
class Animal
{
public function __construct(
protected string $name,
protected int $age
) {}
public function speak(): string
{
return "..."; // base implementation
}
public function describe(): string
{
return "{$this->name} says: " . $this->speak();
}
protected function makeSound(string $sound): string
{
return $sound;
}
}
class Dog extends Animal
{
public function __construct(string $name, int $age, private string $breed)
{
parent::__construct($name, $age); // MUST call parent constructor
}
// Override speak() — polymorphism
public function speak(): string
{
return $this->makeSound("Woof!"); // can call parent's protected method
}
public function getBreed(): string { return $this->breed; }
}
class Cat extends Animal
{
public function speak(): string { return "Meow!"; }
}
$animals = [new Dog('Rex', 3, 'German Shepherd'), new Cat('Whiskers', 5)];
foreach ($animals as $animal) {
echo $animal->describe() . "\n"; // polymorphic dispatch
}
// "Rex says: Woof!"
// "Whiskers says: Meow!"
// Checking hierarchy
$dog = new Dog('Rex', 3, 'GSD');
var_dump($dog instanceof Dog); // true
var_dump($dog instanceof Animal); // true — inheritance chain
// parent:: in override
class LoggingDog extends Dog
{
public function speak(): string
{
$sound = parent::speak(); // calls Dog::speak
error_log("{$this->name} spoke: $sound");
return $sound;
}
}
// final class — cannot be extended
final class ImmutablePoint
{
public function __construct(
public readonly float $x,
public readonly float $y
) {}
}
// class MyPoint extends ImmutablePoint {} // Fatal Error