## Herança de Objetos

Herança é um conceito de programação estabelecido, e o PHP faz uso deste em seu modelo de objetos. Este princípio afeta a forma com que classes e objetos se relacionam com outras.

Por exemplo, ao estender uma classe, a subclasse herda todos os métodos públicos e protegidos, propriedades e constantes da classe pai. A não que uma classe sobrescreva estes métodos, eles manterão sua funcionalidade original.

Isto é útil para definir uma funcionalidade abstrata, e permitir a implementação de uma funcionalidade adicional em objetos similares sem a necessidade de reimplementar todas as funcionalidades compartilhadas.

Os métodos privados de uma classe pai não são acessíveis a uma classe filha. Como resultado, as classes filhas podem reimplementar um método privado sem levar em conta as regras normais de herança. Antes do PHP 8.0.0, entretanto, as restrições `final` e `static` eram aplicadas aos métodos privados. Desde o PHP 8.0.0, a única restrição de método privado que é aplicada é `private final` para construtores, já que essa é uma maneira comum de "desabilitar" o construtor ao usar métodos de fábrica estáticos.

A visibilidade de métodos, propriedades e constantes pode ser relaxada, por exemplo, um método com `protected` pode ser marcado como `public`, mas não pode ser restrito, por exemplo, marcar uma propriedade que tenha `public` como `private`. Uma exceção são os construtores, cuja visibilidade pode ser restrita, ou seja, um construtor `public` pode ser declarado como `private` numa classe filha.

> Nota:

> A não ser que o autoload seja usado, as classes devem ser definidas antes de utilizadas. Se uma classe estende outra, a classe pai deve ser declarada antes da estrutura da classe filha. Esta regra se aplica a classes que herdam outras classes e interfaces.

> Nota:

> Não é permitido sobrescrever uma propriedade de leitura/gravação com um propriedade somente de leitura ou vice-versa.

>     <?php

>     class A {
>         public int $prop;
>     }
>     class B extends A {
>         // Ilegal: leitura-gravação -> somente-leitura
>         public readonly int $prop;
>     }
>     ?>

Exemplo #1 Exemplo de Herança

    <?php

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

        public function printPHP()
        {
            echo 'PHP é ótimo' . PHP_EOL;
        }
    }

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

    $foo = new Foo();
    $bar = new Bar();
    $foo->printItem('baz'); // Saída: 'Foo: baz'
    $foo->printPHP();       // Saída: 'PHP é ótimo'
    $bar->printItem('baz'); // Saída: 'Bar: baz'
    $bar->printPHP();       // Saída: 'PHP é ótimo'

    ?>

### Compatibilidade de Tipo de Retorno com Classes Internas

Antes do PHP 8.1, a maioria das classes ou métodos internos não declaravam seus tipos de retorno, e qualquer tipo de retorno era permitido ao estendê-los.

A partir do PHP 8.1.0, a maioria dos métodos internos começaram a declarar seu tipo de retorno de forma "experimental", nesse caso o tipo de retorno dos métodos deve ser compatível com o pai sendo estendido, do contrário, um aviso de descontinuação é emitido. Note que a ausência de uma declaração de retorno explícita também é considerada uma incompatibilidade de assinatura e, portanto, resulta no aviso de descontinuação.

Se o tipo de retorno não puder ser declarado para um método que sobrepõe devido à preocupações com compatibilidade entre versões PHP, um atributo ReturnTypeWillChange pode ser adicionado para silenciar o aviso de descontinuação.

Exemplo #2 O método que sobrepõe não declara nenhum tipo de retorno

    <?php
    class MeuDateTime extends DateTime
    {
        public function modify(string $modifier) { return false; }
    }

    // "Deprecated: Return type of MeuDateTime::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" a partir do PHP 8.1.0
    ?>

Exemplo #3 O método que sobrepõe declara um tipo de retorno errado

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

    // "Deprecated: Return type of MeuDateTime::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" a partir do PHP 8.1.0
    ?>

Exemplo #4 O método que sobrepõe declara um tipo de retorno errado sem um aviso de descontinuação

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

    // Nenhum aviso é emitido
    ?>

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