• 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 14/06/2024

Contrôlez l'accès aux propriétés et aux méthodes de vos objets

Félicitations ! Vous commencez à structurer votre code avec de plus en plus d'expertise. 😎

Souvent, lorsque vous allez obtenir une technique donnant des possibilités d'extension d'un code, vous allez aussi croiser des situations où vous auriez aimé, au contraire, restreindre les accès à certaines propriétés ou méthodes. C'est ce que nous allons voir dans ce chapitre.

Empêchez l'accès aux propriétés et aux méthodes

Nous avons déjà croisé 2 formes de visibilité, publique et privée, dans la première partie. Mais jusqu'ici, c'était uniquement via une seule classe. Que se passe-t-il lorsque je définis une propriété ou une méthode comme privée, puis que j'hérite de cette classe ?

Changeons la classe User  en passant tout en private  :

<?php

declare(strict_types=1);

class User
{
    private const STATUS_ACTIVE = 'active';
    private const STATUS_INACTIVE = 'inactive';

    public function __construct(private string $username, private string $status = self::STATUS_ACTIVE)
    {
    }

    private function setStatus(string $status): void
    {
        assert(
            in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE]),
            sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE]))
        );
    
        $this->status = $status;
    }
    
    private function getStatus(): string
    {
        return $this->status;
    }
}


class Admin extends User
{
    public const STATUS_LOCKED = 'locked';
  
    // la méthode est entièrement ré-écrite ici :) seule la signature reste inchangée
    public function setStatus(string $status): void
    { 
        assert(
            in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_LOCKED]),
            sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_LOCKED]))
        );
    
        $this->status = $status;
    }
    
    // la méthode utilise celle de la classe parente, et ajoute un comportement :)
    public function getStatus(): string
    {
        return strtoupper(parent::getStatus());
    }
}


$admin = new Admin('Paddington');
$admin->setStatus(Admin::STATUS_LOCKED);
echo $admin->getStatus();

Tester ce code.

C'est bien malin ! Plus aucune des méthodes surchargées de la classe Admin  ne fonctionne ! Ce code me renvoie une erreur. PHP va m'indiquer que j'ai tenté d'accéder à une méthode privée, ou encore que les propriétés auxquelles nous tentons d’accéder n’existent pas...

Un élément privé devient uniquement accessible pour la classe dans laquelle il se trouve. L'héritage est interrompu pour cet élément, qu'il s'agisse d'une propriété ou d'une méthode.

Heureusement, nous avons accès à une troisième visibilité nous apportant un peu de finesse.

Autorisez l'accès uniquement aux enfants

Cette visibilité s'applique par le biais du mot clé protected. Donc pour synthétiser, ‌nous avons 3 moyens d'exposer nos propriétés et nos méthodes :

  • public  ouvre l'accès à tous ;

  • private  ferme à tous ;

  • et protected  permet de fermer à l'extérieur, mais d'ouvrir à l'héritage

Pour une classe privé, aucune classe ne peut y accéder. Pour une classe protégé, seulement ses classes enfant peuvent y accéder. Pour une classe public, toute classe peut y accéder.
Représentation du mécanisme de visibilité

protected  est un entre-deux idéal pour définir une méthode dont le but n'est que d'être appelée en interne, dont un développeur utilisant la classe n'a pas vraiment à connaître l'existence, mais en autorisant qu'elle soit manipulée depuis une classe enfant.

Changeons à nouveau notre classe User  pour lui appliquer la visibilité protected.

<?php

declare(strict_types=1);

class User
{
    protected const STATUS_ACTIVE = 'active';
    protected const STATUS_INACTIVE = 'inactive';

    public function __construct(protected string $username, protected string $status = self::STATUS_ACTIVE)
    {
    }

    protected function setStatus(string $status): void
    {
        assert(
            in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE]),
            sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE]))
        );
    
        $this->status = $status;
    }
    
    protected function getStatus(): string
    {
        return $this->status;
    }
}


class Admin extends User
{
    public const STATUS_LOCKED = 'locked';
  
    // la méthode est entièrement ré-écrite ici :) seule la signature reste inchangée
    public function setStatus(string $status): void
    { 
        assert(
            in_array($status, [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_LOCKED]),
            sprintf('Le status %s n\'est pas valide. Les status possibles sont : %s', $status, implode(', ', [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_LOCKED]))
        );
    
        $this->status = $status;
    }
    
    // la méthode utilise celle de la classe parente, et ajoute un comportement :)
    public function getStatus(): string
    {
        return strtoupper(parent::getStatus());
    }
}


$admin = new Admin('Paddington');
$admin->setStatus(Admin::STATUS_LOCKED);
echo $admin->getStatus();

Tester ce code.

Cette fois-ci, le code fonctionne ! 😀

Nous avons accès à la méthode depuis les classes enfants.

Bon, j’y suis allé un peu fort dans l’exemple. En réalité, ici, les constantes seraient probablement déclarées publiques, les propriétés en protégé, les accesseurs et les mutateurs en public, et les méthodes “internes” (qui ne devraient être utilisées que par la classe elle-même) en privé, ou protégées, selon l’usage. :)

‌En résumé

  • En utilisant le mot clé private, vous empêchez quiconque autre que la classe courante de manipuler les propriétés et méthodes.

  • En utilisant le mot clé protected, vous donnez l'autorisation à la classe courante ainsi qu'à ses enfants de manipuler les propriétés et méthodes :) ; mais pas aux éléments extérieurs à la classe, ou extérieurs aux objets de cette classe.

  • Et comme nous l’avons vu précédemment, avec le mot-clé  public , il est possible de manipuler la méthode ou la propriété depuis la classe, ses classes enfants et depuis l’extérieur.

  • Autrement dit, pour modifier une propriété depuis un enfant, il faut qu’elle possède la visibilité public ou protected, ou qu’elle possède un mutateur.

Restreindre la visibilité et la portée des actions d’une classe permet de réduire le champ des possibles pour un utilisateur de cette classe. Moins d’erreurs seront à venir. C’est top ! Si des mécanismes sont prévus pour la restriction, eh bien il existe aussi des mécanismes inverses ! Des mécanismes contraignants à l’ouverture ; plus précisément, à l’extension. Voyons cela dans le prochain chapitre. 

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