• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

Ce cours existe en livre papier.

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 21/08/2023

Procédez à un héritage

Vous savez à présent créer des objets ! Mais les objets seuls ne proposent qu'une encapsulation de code. Il faut commencer à structurer votre code pour réduire les répétitions et donner du sens aux objets.

Voyons ensemble la mécanique de la programmation orientée objet qui nous aidera à réduire la duplication de code : l’héritage. L'héritage nous permet d’accéder aux propriétés et méthodes d’une classe “parent” depuis les “enfants”. Voyons comment cela marche à travers notre fil rouge MatchMaker.

Découvrez la mécanique de l'héritage

Regardons ce code, permettant de définir un utilisateur :

<?php
 
declare(strict_types=1);
 
class User
{
    private const STATUS_ACTIVE = 'active';
    private const STATUS_INACTIVE = 'inactive';
 
    public function __construct(public string $username, private string $status = self::STATUS_ACTIVE)
    {
    }
 
    public function setStatus(string $status): void
    {
        if (!in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE])) {
            trigger_error(sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE])), E_USER_ERROR);
        };

        $this->status = $status;
    }
 
    public function getStatus(): string
    {
        return $this->status;
    }
}

Tester ce code

On remarque qu’un utilisateur est défini par un pseudo et par un statut (actif ou inactif). Nous avons la possibilité de récupérer le statut avec  getStatus et nous pouvons modifier le statut avec  setStatus (qui déclenche une erreur si le statut n’est ni “actif”, ni “inactif”).

Et à présent créons ensemble un administrateur :

<?php
 
declare(strict_types=1);
 
class Admin
{
    private const STATUS_ACTIVE = 'active';
    private const STATUS_INACTIVE = 'inactive';
 
    // Ajout d'un tableau de roles pour affiner les droits des administrateurs :)
    public function __construct(public string $username, private array $roles = [], private string $status = self::STATUS_ACTIVE)
    {
    }
 
    public function setStatus(string $status): void
    {
        if (!in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE])) {
            trigger_error(sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE])), E_USER_ERROR);
        };
 
        $this->status = $status;
    }
 
    public function getStatus(): string
    {
        return $this->status;
    }
 
    // Méthode d'ajout d'un rôle, puis on supprime les doublons avec array_filter.
    public function addRole(string $role): void
    {
        $this->roles[] = $role;
        $this->roles = array_filter($this->roles);
    }

    // Méthode de renvoie des rôles, dans lequel on définit le rôle ADMIN par défaut.
    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ADMIN';

        return $roles;
    }
 
    public function setRoles(array $roles): void
    {
        $this->roles = $roles;
    }
}

Tester ce code

Voyez-vous des choses similaires entre les deux ? Dans les deux classes nous retrouvons des propriétés similaires, comme le nom et le statut. Il y a aussi des méthodes en commun pour la gestion du statut. La seule différence est l’ajout d’une gestion de rôles dans l’admin. C’est dommage d’avoir à répéter ce code.

En imaginant créer une classe  Joueur, il est très probable que nous retrouverions de nouveau des similitudes avec le  User. L’héritage va nous permettre de supprimer les parties dupliquées. Voyons ensemble comment faire en étendant les classes.

Étendez une classe

Nous allons modifier notre classe   Admin  pour qu’elle bénéficie du code de la classe   User. Avec l’héritage, la classe hérite des propriétés, ainsi que des méthodes des classes "parentes". Voyez ceci exactement comme un arbre généalogique :

Une classe enfant, ici emboîtée dans une classe parent, hérite les attributs de cette classe parente. Sa classe petit enfant hérite ses attributs.
La classe enfant hérite les attributs de sa classe parente

Pour imager, pensez à une usine de fabrication de boîtes : certains modèles sont en carton, d’autres en fer… ce sont des variations (différentes instances) d’une classe. Puis vous ajoutez une poignée de transport. Vous avez la même base de boîte sur la chaîne de fabrication, mais à la fin vous y ajoutez un élément en plus, vous lui avez ajouté du comportement. Il s’agit ici d’héritage, vous avez “étendu” la boîte.

Utilisez une classe qui servira de base commune avec le mot clé extends

Avoir du code dupliqué dans différentes classes est rarement une bonne idée. Même s’il n’est dupliqué qu’une seule fois, cela peut poser des problèmes. Si vous souhaitez modifier votre code, il faudra reporter les modifications. Vous risquez alors des oublis et des incohérences. Il faut donc factoriser le code afin d'éviter cette situation, c’est-à-dire fusionner le code identique. Si vous pouvez éviter la duplication en repérant des appartenances communes entre vos objets, alors c'est idéal d'utiliser l'héritage (d’ailleurs vos éditeurs modernes sont capables de vous le signaler). Faisons en sorte que notre classe  Admin hérite de la classe   User.

Pour ce faire, nous allons employer le mot clé extends, suivi du nom de la classe que nous souhaitons étendre : Admin extends User. Cela signifiera donc que nos administrations bénéficieront de toutes les propriétés et méthodes de la classe  User. Le mot-cléextendspeut se lire par “est un” : un administrateur est un utilisateur (avec des droits spécifiques). L’héritage est donc complètement adapté.

Modifions la classe de notre exemple :

<?php
 
declare(strict_types=1);
 
class User
{
    public const STATUS_ACTIVE = 'active';
    public const STATUS_INACTIVE = 'inactive';
 
    public function __construct(public string $username, public string $status = self::STATUS_ACTIVE)
    {
    }

    public function setStatus(string $status): void
    {
        if (!in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE])) {
            trigger_error(sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE])), E_USER_ERROR);
        };

        $this->status = $status;
    }

    public function getStatus(): string
    {
        return $this->status;
    }
}
 
class Admin extends User
{
    // Ajout d'un tableau de roles pour affiner les droits des administrateurs :)
    public function __construct(public string $username, public array $roles = [], public string $status = self::STATUS_ACTIVE)
    {
    }
 
    // Méthode d'ajout d'un rôle, puis on supprime les doublons avec array_filter.
    public function addRole(string $role): void
    {
        $this->roles[] = $role;
        $this->roles = array_filter($this->roles);
    }
 
    // Méthode de renvoie des rôles, dans lequel on définit le rôle ADMIN par défaut.
    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ADMIN';
 
        return $roles;
    }

    public function setRoles(array $roles): void
    {
        $this->roles = $roles;
    }
}

Tester ce code

Le code est maintenant bien plus léger à lire. 🙂 Puisque nous avons éliminé du code, c'est aussi moins de risque d'erreur, d'oubli lors d'une mise à jour, un code simplifié et moins de mémoire utilisée par PHP. Que du bon en fait ! 😀

Toutes les méthodes, les propriétés et les constantes de la classe parenteUser) seront accessibles dans la classe enfant (Admin), c’est ce que nous allons faire sur le chapitre suivant. 

Dans cet exemple, nous avons utilisé l'héritage entre 2 classes. Nous pouvons continuer ainsi de manière infinie afin d'avoir un enfant d'un enfant, d'un enfant, d'un enfant, …, d’une classe parente.

En résumé

  • L’héritage nous permet de passer les propriétés et méthodes d’une classe “parent” à des classes “enfants”.

  • Vous pouvez structurer votre code et éviter la duplication en héritant d’une classe.

  • L’héritage s’effectue avec l’usage du mot clé   extends  juste après le nom de la classe à étendre, suivi de la classe dont il faut hériter.

Maintenant que vous savez pourquoi et comment mettre en place l’héritage, nous allons découvrir dans le prochain chapitre comment profiter des propriétés et méthodes héritées. Quand vous serez prêt, suivez-moi !

Exemple de certificat de réussite
Exemple de certificat de réussite