# PHP para Iniciantes - Classes e Objetos - Herança

Olá, devs incríveis e maravilhoses. Tudo certinho com vocês?! Eu consegui um tempinho para escrever esse artigo, então acho que estou bem, haha.

O assunto de hoje vai ser mais um pequeno salto no fluxo atual da documentação oficial do PHP, pois ao invés de falarmos somente sobre **[Visibilidade](https://www.php.net/manual/pt_BR/language.oop5.visibility.php)**, falaremos de **[Herança](https://www.php.net/manual/pt_BR/language.oop5.inheritance.php)**.

> Ué, Kiko... Por que pularemos esse assunto?

Pelo simples fato de que eu já falei sobre ele. Lembra das palavras `public`, `private` e `protected`? Eu expliquei nos artigos onde esse tópico estava relevante:

1. [Visibilidade de Propriedades](https://blog.kaiquegarcia.dev/php-para-iniciantes-classes-o-objetos-propriedades) (procura por **1.1.1**);
2. [Visibilidade de Métodos](https://blog.kaiquegarcia.dev/php-para-iniciantes-classes-e-objetos-o-basico) (procura por **3. O que é e como declarar métodos**).

Ainda assim, há um pequeno detalhe que não falei a respeito: **[visibilidade em outros objetos](https://www.php.net/manual/pt_BR/language.oop5.visibility.php#language.oop5.visibility-other-objects)**. Vou dedicar essa introdução para isso, ok? Afinal, está relacionado com **herança**.

## Visibilidade entre objetos

A visibilidade que damos às propriedades e métodos pertence à assinatura da classe que estamos desenvolvendo. Isso significa que mesmo que você escreva uma propriedade privada, instâncias diferentes da mesma classe poderão acessar esse valor. Basta injetar a outra instância em algum método:

```php
<?php

class Exemplo {
    public function __construct(
        private int $codigo
    ) { }

    public static function imprime($ex Exemplo) {
        echo $ex->codigo;
        // $ex->codigo é uma propriedade privada da instância $ex
        // mas eu consigo acessar seu valor, pois estamos dentro da classe que conhece toda a assinatura dele
    }
}

$ex = new Exemplo(123);
Exemplo::imprime($ex);
```

Notou que o método estático `imprime` está recebendo um objeto da classe `Exemplo`? E que esse método também pertence à classe `Exemplo`? Dessa forma, é possível trabalhar com todas as propriedades e métodos privados de `$ex`.

> E o que isso tem a ver com herança, Kiko?

**Tudo**. Nós podemos acessar propriedades protegidas de outra classe, se estiver herdada na classe atual. É por isso que digo que a visibilidade entre objetos faz parte de herança.

```php
<?php

class Person {
	public function __construct(
		protected string $name
	) { }
}

class Pilot extends Person {
	public function criticize(Person $person): void {
		echo $person->name . " ainda tem muito o que aprender..." . PHP_EOL;
	}
}

$john = new Person("John Doe");


$pilot = new Pilot("José");
$pilot->criticize($john);
```

Veja o código funcionando: <https://onlinephp.io/c/b7bb0>

1. `$person->name` é uma propriedade protegida de `Person`;
2. `Pilot` extende `Person`, logo ele herda todos os métodos e propriedades protegidos e públicos de `Person`, incluindo `$person->name`;
3. Quando `Pilot` recebe um objeto `Person`, ele pode acessar tudo aquilo que herdou dele.

É por isso que vemos por aí o pessoal divulgando herança sempre como uma relação Pai e Filho. Hoje vou quebrar um pouco esse ciclo vicioso:

```php
<?php

class Mae {
    protected array $imoveis;
    protected array $contasBancarias;
}

class Filho extends Mae { }
```

Esse exemplo faz sentido e, ao mesmo tempo, não faz.

<center>
![MEME: é o que, véi?](https://media.giphy.com/media/xTiTnDAP0RiCo9k85W/giphy.gif)
</center>

> Como é, Kiko?

Olhando somente pela herança entre as classes, nós entendemos que a classe `Filho` herda as propriedades `imoveis` e `contasBancarias` da classe `Mae`. Porém, da forma como está, `Filho` herda tudo, não somente bens e dinheiro. Se a gente cria uma propriedade que define o emprego da mãe, o filho estaria herdando isso também... E na vida real, a gente sabe que isso não faz sentido algum, não é mesmo?

Se fossemos replicar a herança da vida real, esse relacionamento seria limitado aos objetos e não às classes. O que poderíamos fazer é criar uma abstração, definindo o que é uma pessoa e criando relacionamento entre pessoas, sem herança:

```php
<?php

class Pessoa {
    protected array $imoveis;
    protected array $contasBancarias;
    protected Pessoa|null $pai; // sutilidade triste aqui, mas é realidade. Se você se identificou, força! Eu te respeito muito.
    protected Pessoa $mae;

    public function herancaMaternal() {
        array_push($this->imoveis, $this->mae->imoveis...);
        // na real, aqui a gente precisa dividir com os irmãos ainda, né? mas vamos deixar assim só pra explicar o que eu tava falando
        array_push($this->contasBancarias, $this->mae->contasBancarias...);
    }
}
```

Com isso, a pessoa que acionar `$pessoa->herancaMaternal()` só vai receber o que de fato herdou, quando for a hora. Percebeu que eu acessei os atributos protegidos `imoveis` e `contasBancarias` de `$this->mae`? Só foi possível pois a visibilidade de qualquer instância de `Pessoa` nos permite "ver" esses dados naquele bloco.

E com isso, temos uma boa introdução para o artigo...

## Herança

> Oloko, Kiko, isso foi só uma introdução?!

Eu queria que fosse, mas eu já escrevi bastante, né? Hahaha. Pelo menos agora eu vou poder ser um pouco mais direto...

**Resusmo**: herança, em orientação a objeto, é o compartilhamento de recursos entre classes. Se a classe `A` **extende** a classe `B`, ela herda todos os métodos e propriedades públicos e privados dela. Esses métodos e propriedades passam a coexistir tanto em `B` quanto em `A`.

A forma de escrita é na declaração da classe. Até aqui, você me viu declarando classes como `class AlgumaCoisa`, certo? Em herança, a declaração inclui a palavra `extends` que indica de qual classe você está herdando:

```php
<?php

class A { }
class B extends A { } 
class C extends B { }
```

Sim, é possível fazer heranças contínuas.

Um tópico interessante sobre herança é o `override`, ou seja, `sobreescrever` alguma coisa. Uma amostra bem simples disso seria uma classe `A` implementar o método `vibrar()` de um jeito e a classe que a herda reimplementar de outra forma:

```php
<?php

class A {
    public static function vibrar(): void {
        echo "zzz" . PHP_EOL;
    }
}

class B extends A {
    public static function vibrar(): void {
        echo "BZZZZ" . PHP_EOL;
    }
}

class C extends A { }
```

Se você chamar:

* `A::vibrar()`: irá imprimir `zzz`;
* `B::vibrar()`: irá imprimir `BZZZZ`;
* `C::vibrar()`: irá imprimir `zzz`.

Veja o código rodando aqui: <https://onlinephp.io/c/98c0e>

> Ué, por que só `B::vibrar()` está diferente?

Porque ele sobreescreveu o comportamento de `A` ao reimplementar o método `vibrar()`.

Override é um recurso comumente utilizado quando encontramos alguma particularidade no meio das heranças, por isso podemos fazer isso. Mas é preciso tomar cuidado com um pequeno detalhe: antes do PHP 8, nós não tínhamos a capacidade de informar o tipo de dado que cada função e/ou método poderia retornar, por isso sempre foi possível sobreescrever os métodos herdados retornando um tipo de dado completamente diferente.

A partir do PHP 8.1, esse tipo de comportamento gera um aviso de depreciação, o que significa que, muito em breve, essa prática não irá mais funcionar nas novas versões.

Ou seja: precisou reimplementar um método e mudou a assinatura dele? É melhor refatorar enquanto ainda pode... Veja o alerta de depreciação aqui: <https://onlinephp.io/c/c6e6d>.

Na documentação, consta a possibilidade de omitir esse alerta ao aplicar o atributo `#[ReturnTypeWillChange]` acima da assinatura do método ou função, porém não recomendo e nem vou explorar isso... Até porque, se há esse risco nas suas heranças, isso só mostra que você está quebrando o seu código.

O que nos leva à seguinte polêmica...

## Herança é **anti-pattern**

A herança entre classes, apesar de ser bem aceito na programação com abstrações, também pode ser considerado um **anti-pattern** ou **anti-padrão**. O exemplo que dei ali de pessoas, mãe, filho e tal evidencia isso: muitas vezes aplicamos uma lógica de herança porque queremos reduzir código, mas quase sempre estamos enxergando a abstração da forma errada.

Como esse artigo é pra quem nunca viu a parada, eu preciso mostrar o erro acontecendo, não é mesmo? Então vamos lá...

Digamos que nós queremos criar uma classe que represente um fusca e que tenha uma função de buzinar, sendo o som da buzina `"bibii"`.

```php
<?php

class Fusca {
    public function buzinar(): void {
        echo "bibii";
    }
}

$fusca = new Fusca();
$fusca->buzinar();
```

E agora, além do fusca, queremos uma lamborghini, sendo a buzina `"pompom"`.

```php
<?php

class Lamborghini {
    public function buzinar(): void {
        echo "pompom";
    }
}

$lamborghini = new Lamborghini();
$lamborghini->buzinar();
```

> Ué, Kiko... Repetiu tudo?!

Sim, criamos uma repetição de código, onde a única diferença é o som da buzina. Se eu quiser criar uma função que chama essa buzina independente do modelo de carro, nós teremos um problema, pois as classes não tem relação entre si.

Geralmente, a primeira coisa que as pessoas pensam quando querem resolver esse tipo de problema é em herança, pois é a saída mais fácil: ah, pega o que tem em comum, cria uma classe abstrata com isso e pronto.

```php
<?php

abstract class Carro {
    public function buzinar(): void {
        echo static::BUZINA . PHP_EOL;
    }
}

class Fusca extends Carro {
    protected const BUZINA = "bibii";
}

class Lamborghini extends Carro {
    protected const BUZINA = "pompom";
}

// Função genérica para todos os carros
function apertarBuzina(Carro $carro) {
    $carro->buzinar();
}

// Aplicando a função
$fusca = new Fusca();
$lamborghini = new Lamborghini();

apertarBuzina($fusca);
apertarBuzina($lamborghini);
```

Veja o código em ação: <https://onlinephp.io/c/cb978>

> Pô, Kiko, para mim ficou muito legível... Por que isso seria considerado um **anti-pattern**??

Sim, herança pode até deixar tudo mais organizado, porém a manutenabilidade disso é péssima pois criamos **perigos invisíveis**. Por exemplo, para indicar o som da buzina de cada carro, eu preciso declarar a constante `BUZINA`. Se eu escrever um carro sem declarar isso, nós teremos um erro:

```php
<?php

class CarroQuebrado extends Carro { }

$carro = new CarroQuebrado();
$carro->buzinar();
```

Veja o que acontece: <https://onlinephp.io/c/2e033>

Toda vez que precisarmos abstrair alguma coisa no nosso código, o ideal é criarmos uma estrutura rígida que nos force a criar tudo o  que for obrigatório. Essa estrutura rígida é chamada de `interface` e é amplamente utilizada em várias linguagens de programação.

Quando você define uma interface `Carro`, você está dizendo ao interpretador: *olha aqui, cara... Toda vez que alguma classe implementar essa estrutura, obrigue o desenvolvedor a escrever todos esses métodos do mesmo jeitinho que eu estou assinando aqui, ok?!*

E o dev que se vire pra respeitar isso:

```php
<?php

interface ICarro { // colocamos o I na frente pra deixar claro que é uma interface
    public function obterBuzina(): string
}
```

Diferente de herança, a declaração de uma interface é precedido pela palavra-chave `interface`. Em herança, nós declaramos classes mesmo... Da mesma forma, para declarar que uma classe está seguindo as regras de uma interface, nós usamos a palavra-chave `implements`, diferente do `extends` da herança.

Toda classe que implementar a interface `ICarro` precisará ter um método `obterBuzina()` que retorna uma `string`. Com isso, a gente pode recriar aquelas classes `Fusca` e `Lamborghini` para parar de usar herança e passar a assinar a nova interface:

```php
class Fusca implements ICarro {
	public function obterBuzina(): string {
		return "bibii";
	}
}

class Lamborghini implements ICarro {
	public function obterBuzina(): string {
		return "pompom";
	}
}
```

Ficou um pouco mais verboso? Ficou, duas linhas... Ainda assim, as próximas classes de carro que forem criadas não terão o risco de alguém esquecer de escrever o que é obrigatório.

> Mas Kiko, cadê o método `buzinar`?

É aqui que fica o pulo do gato: apesar de fazer total sentido colocar um método `buzinar` nos carros, nós podemos criar uma função que faça a buzina em si... Afinal, na outra implementação, nós teríamos de criar essa função do mesmo jeito, lembra? Tínhamos `carro->buzinar` dentro de `apertarBuzina($carro)`.

Agora só precisamos do `apertarBuzina($carro)`:

```php
function apertarBuzina(ICarro $carro): void {
	echo $carro->obterBuzina() . PHP_EOL;
}

$fusca = new Fusca();
$lamborghini = new Lamborghini();

apertarBuzina($fusca);
apertarBuzina($lamborghini);
```

Veja o código funcionando aqui: <https://onlinephp.io/c/cd215>

Então mesmo herança sendo muito legal, tente pensar um pouco além, tudo bem? Você precisa fazer um código com o menor risco possível de erros acidentais. Pense sempre que outro desenvolvedor vai precisar mexer: é melhor força-lo a seguir um padrão do que criar padrões invisíveis, concorda?

E por hoje é só!! Curtiu? **Comenta e compartilha**! Acho que, com esse artigo, consegui deixar bem claro o motivo de herança ser considerado um **anti-pattern**... Ou você ainda discorda? Você teria feito esse exercício dos carros diferente? Pode mandar aí nos comentários, hehe.

No próximo artigo, falaremos sobre **[Operador de Resolução de Escopo (::)](https://www.php.net/manual/pt_BR/language.oop5.paamayim-nekudotayim.php)**, que é o que usamos para acessar propriedades e métodos estáticos das classes. Tá preparade?

**Inté!!**
