## Héritage

L'héritage est un des grands principes de la programmation orientée objet (POO), et PHP l'implémente dans son modèle objet. Ce principe va affecter la manière dont de nombreuses classes sont en relation les unes avec les autres.

Par exemple, lorsqu'une classe est étendue, la classe enfant hérite de toutes les méthodes publiques et protégées, propriétés et constantes de la classe parente. Tant qu'une classe n'écrase pas ces méthodes, elles conservent leur fonctionnalité d'origine.

L'héritage est très utile pour définir et abstraire certaines fonctionnalités communes à plusieurs classes, tout en permettant la mise en place de fonctionnalités supplémentaires dans les classes enfants, sans avoir à réimplémenter en leur sein toutes les fonctionnalités communes.

Les méthodes privées d'une classe parente ne sont pas accessibles à la classe enfant. Par conséquent, les classes enfant peuvent réimplémenter une méthode privée elles-mêmes sans se soucier des règles d'héritage normales. Avant PHP 8.0.0, cependant, les restrictions `final` et `static` étaient appliquées aux méthodes privées. À partir de PHP 8.0.0, l'unique restriction de méthode privée qui est imposée est `private final` sur les constructeurs, car c'est une manière courante pour "désactiver" le constructeur lors de l'utilisation de méthodes factory statiques à la place.

La visibilité des méthodes, propriétés et constantes peut être relaxée, c.-à-d. une méthode `protected` peut être marquée comme `public`, mais elles ne peuvent pas être restreintes, e.g. marquer une propriété `public` comme `private`. Une exception sont les constructeurs, pour lesquels la visibilité peut être restreinte, par exemple un constructeur `public` peut être annoté en tant que `private` dans la classe enfant.

> Note:

> À moins que l'autochargement ne soit utilisé, les classes doivent être connues avant d'être utilisées. Les classes mères doivent être définies avant l'écriture d'un héritage. Cette règle générale s'applique aussi dans le cas d'héritage ou d'implémentation d'interfaces.

> Note:

> Il n'est pas autorisé de redéfinir une propriété en lecture-écriture avec une propriété en lecture seule ou vice versa.

>     <?php

>     class A {
>         public int $prop;
>     }
>     class B extends A {
>         // Illégal : lecture-écriture -> lecture seule
>         public readonly int $prop;
>     }
>     ?>

Exemple #1 Exemple d'héritage

    <?php

    class Foo
    {
        public function printItem($string)
        {
            echo 'Foo: ' . $string . PHP_EOL;
        }

        public function printPHP()
        {
            echo 'PHP est super.' . PHP_EOL;
        }
    }

    class Bar extends Foo
    {
        public function printItem($string)
        {
            echo 'Bar: ' . $string . PHP_EOL;
        }
    }

    $foo = new Foo();
    $bar = new Bar();
    $foo->printItem('baz'); // Affiche : 'Foo: baz'
    $foo->printPHP();       // Affiche : 'PHP est super.'
    $bar->printItem('baz'); // Affiche : 'Bar: baz'
    $bar->printPHP();       // Affiche : 'PHP est super.'

    ?>

### Compatibilité des types de retour avec les classes internes

Avant PHP 8.1, la plupart des classes ou méthodes internes ne déclaraient pas leur type de retour, et tout type de retour était autorisé lors de leur héritage.

À partir de PHP 8.1.0, la plupart des méthodes internes ont commencé à déclarer "provisoirement" leur type de retour, dans ce cas, le type de retour des méthodes doit être compatible avec la classe parent; Dans le cas contraire, une notification de dépréciation est émise. Il est à noter que l'absence d'une déclaration de retour explicite est également considérée comme une erreur de signature, et entraîne donc l'avis de dépréciation.

Si le type de retour ne peut être déclaré pour une méthode de surcharge en raison de problèmes de compatibilité entre versions de PHP, un attribut ReturnTypeWillChange peut être ajouté pour passer sous silence l'avis de dépréciation.

Exemple #2 La méthode surchargée ne déclare pas de type de retour.

    <?php

    class MyDateTime extends DateTime
    {
        public function modify(string $modifier) { return false; }
    }

    // "Deprecated: Return type of MyDateTime::modify(string $modifier) should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" À partir de PHP 8.1.0

Exemple #3 La méthode surchargée déclare un mauvais type de retour.

    <?php

    class MyDateTime extends DateTime
    {
        public function modify(string $modifier): ?DateTime { return null; }
    }

    // "Deprecated: Return type of MyDateTime::modify(string $modifier): ?DateTime should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" À partir de PHP 8.1.0

Exemple #4 La méthode surchargée déclare un mauvais type de retour sans notice de dépréciation.

    <?php

    class MyDateTime extends DateTime
    {
        /**
         * @return DateTime|false
         */
        #[\ReturnTypeWillChange]
        public function modify(string $modifier) { return false; }
    }

    // Aucune notice n'est déclenchée

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open