Lesson 3/6 10 min

Inheritance and abstract classes

extends, parent::, overriding a method, and abstract classes as templates. Inheritance in PHP, with runnable code.

FR EN

extends : hériter d'une classe

Un CompteEpargne est un Compte avec un taux en plus. En PHP, on l'écrit avec extends : la classe fille récupère toutes les propriétés et méthodes public/protected du parent.

class Compte {
    protected float $solde = 0;        // protected → accessible aux filles
    public function deposer(float $m): void { if ($m > 0) $this->solde += $m; }
    public function getSolde(): float { return $this->solde; }
}

class CompteEpargne extends Compte {
    public function __construct(private float $taux) {}

    public function ajouterInterets(): void {
        $this->deposer($this->solde * $this->taux);  // réutilise la méthode héritée
    }
}

Remarque : $solde est protected (pas private) pour rester accessible à la classe fille. private resterait invisible même pour les enfants.

Hiérarchie d'héritage : Compte parent, CompteEpargne et CompteCourant enfants Compte # solde : float + deposer() + getSolde() CompteEpargne - taux : float + ajouterInterets() CompteCourant - decouvert : float + retirer() override extends extends
Les classes filles héritent des membres public/protected du parent, puis ajoutent ou redéfinissent.

parent:: et la redéfinition

Une fille peut redéfinir (override) une méthode du parent, et appeler la version parente avec parent::. Si la fille a son propre constructeur, elle doit appeler parent::__construct(...) pour initialiser la partie héritée.

class CompteCourant extends Compte {
    public function __construct(private float $decouvertAutorise) {
        parent::__construct();   // construit la partie "Compte"
    }
    // on REDÉFINIT retirer pour autoriser un découvert
    public function retirer(float $m): bool {
        if ($m > 0 && $m <= $this->solde + $this->decouvertAutorise) {
            $this->solde -= $m;
            return true;
        }
        return false;
    }
}

Les classes abstraites : un gabarit

Une classe abstraite ne peut pas être instanciée directement : c'est un gabarit pour ses filles. Elle peut imposer des méthodes abstraites (sans corps) que chaque fille doit implémenter.

abstract class Forme {
    abstract public function aire(): float;   // pas de corps : à implémenter

    public function decrire(): string {        // méthode concrète partagée
        return "Aire = " . $this->aire();
    }
}
class Carre extends Forme {
    public function __construct(private float $cote) {}
    public function aire(): float { return $this->cote ** 2; }
}
// new Forme();  // ❌ Error: Cannot instantiate abstract class Forme

Exécute : héritage en action

<?php
class Compte {
    protected float $solde = 0;
    public function deposer(float $m): void { if ($m > 0) $this->solde += $m; }
    public function getSolde(): float { return $this->solde; }
}
class CompteEpargne extends Compte {
    public function __construct(private float $taux) {}
    public function ajouterInterets(): void {
        $this->deposer($this->solde * $this->taux);
    }
}

$e = new CompteEpargne(0.05);
$e->deposer(1000);        // méthode HÉRITÉE de Compte
$e->ajouterInterets();    // méthode PROPRE → +50
echo "Solde : " . $e->getSolde() . " €\n";  // 1050
?>
Accepter ou rejeter le code de l'IA

Tu veux un compte de support avec un plafond de retrait. L'IA te propose de faire hériter CompteSupport de CompteEpargne et passe $solde en public. Tu acceptes tel quel, ou tu rejettes ? Justifie.

class CompteSupport extends CompteEpargne {  // CompteEpargne a déjà ajouterInterets()
    public float $solde = 0;                 // public : on y accède de partout
    public function retirer(float $m): void {
        if ($m <= 1000) $this->solde -= $m;  // plafond codé en dur
    }
}
À rejeter. Deux fautes. 1) public float $solde casse l'encapsulation : n'importe quel code peut écrire $compte->solde = 999999 sans passer par deposer(). Le parent l'avait à juste titre en protected ; ici on l'expose pour rien. 2) Héritage abusif : un compte de support n'est pas un compte épargne, il hérite donc d'ajouterInterets() qui n'a aucun sens pour lui. La règle « est-un » n'est pas respectée. Le bon réflexe : garder $solde en protected et faire hériter CompteSupport de Compte (ou d'une classe/interface adaptée), pas d'CompteEpargne.
Rappel libre

Sans remonter dans la leçon : pourquoi met-on $solde en protected plutôt qu'en private dans Compte, et qu'est-ce qui empêche d'écrire new Forme() sur une classe abstraite ?

protected rend $solde accessible à la classe fille (ex. CompteEpargne qui lit $this->solde dans ajouterInterets()) ; private le rendrait invisible même pour les enfants. Pour la classe abstraite : abstract class Forme ne peut pas être instanciée parce qu'elle déclare au moins une méthode abstraite sans corps (aire()) ; PHP lève « Cannot instantiate abstract class Forme ». Elle sert de gabarit : seules ses filles, qui implémentent aire(), sont instanciables.
Quel mot-clé fait hériter une classe d'une autre en PHP ?
Une classe abstraite…
Prochaine étape

L'abstraction « impose un contrat ». PHP a un outil dédié pour ça, plus souple que l'héritage : les interfaces.

Leçon 4 : interfaces →

extends: inheriting from a class

A CompteEpargne is a Compte with an extra rate. In PHP, you write it with extends: the child class gets all the parent's public/protected properties and methods.

class Compte {
    protected float $solde = 0;        // protected → accessible to children
    public function deposer(float $m): void { if ($m > 0) $this->solde += $m; }
    public function getSolde(): float { return $this->solde; }
}

class CompteEpargne extends Compte {
    public function __construct(private float $taux) {}

    public function ajouterInterets(): void {
        $this->deposer($this->solde * $this->taux);  // reuses the inherited method
    }
}

Note: $solde is protected (not private) so it stays accessible to the child class. private would be invisible even to children.

Inheritance hierarchy: Compte parent, CompteEpargne and CompteCourant children Compte # solde : float + deposer() + getSolde() CompteEpargne - taux : float + ajouterInterets() CompteCourant - decouvert : float + retirer() override extends extends
Child classes inherit the parent's public/protected members, then add or override.

parent:: and overriding

A child can override a parent method, and call the parent version with parent::. If the child has its own constructor, it must call parent::__construct(...) to initialize the inherited part.

class CompteCourant extends Compte {
    public function __construct(private float $decouvertAutorise) {
        parent::__construct();   // builds the "Compte" part
    }
    // we OVERRIDE retirer to allow an overdraft
    public function retirer(float $m): bool {
        if ($m > 0 && $m <= $this->solde + $this->decouvertAutorise) {
            $this->solde -= $m;
            return true;
        }
        return false;
    }
}

Abstract classes: a template

An abstract class can't be instantiated directly: it's a template for its children. It can require abstract methods (no body) that each child must implement.

abstract class Forme {
    abstract public function aire(): float;   // no body: must be implemented

    public function decrire(): string {        // shared concrete method
        return "Area = " . $this->aire();
    }
}
class Carre extends Forme {
    public function __construct(private float $cote) {}
    public function aire(): float { return $this->cote ** 2; }
}
// new Forme();  // ❌ Error: Cannot instantiate abstract class Forme

Run it: inheritance in action

<?php
class Compte {
    protected float $solde = 0;
    public function deposer(float $m): void { if ($m > 0) $this->solde += $m; }
    public function getSolde(): float { return $this->solde; }
}
class CompteEpargne extends Compte {
    public function __construct(private float $taux) {}
    public function ajouterInterets(): void {
        $this->deposer($this->solde * $this->taux);
    }
}

$e = new CompteEpargne(0.05);
$e->deposer(1000);        // method INHERITED from Compte
$e->ajouterInterets();    // OWN method → +50
echo "Balance: " . $e->getSolde() . " €\n";  // 1050
?>
Next step

Abstraction "enforces a contract". PHP has a dedicated tool for that, more flexible than inheritance: interfaces.

Lesson 4: interfaces →
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement