Menu

Herança em PHP: extends, parent:: e sobrescrita

No PHP, uma classe herda de outra com class Dog extends Animal: ela recebe as propriedades e os métodos public e protected da classe pai, pode sobrescrevê-los e ainda pode chamar o original com parent::method(). Veja sobrescrita, protected, final, instanceof e a armadilha dos métodos privados.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

No PHP, uma classe herda de outra com extends: class Dog extends Animal dá a Dog todas as propriedades e métodos public e protected de Animal. A filha pode adicionar novos métodos, sobrescrever os herdados declarando um método com o mesmo nome e chamar o original com parent::method().

Dog não tem construtor, então usa o de Animal, e é por isso que new Dog('Rex') funciona. Uma classe filha só pode estender uma classe pai; o PHP não tem herança múltipla de classes.

Chamar o método da classe pai com parent::

Sobrescrever substitui o método da classe pai por completo. Para estendê-lo em vez de substituí-lo, chame parent::method() na filha e trabalhe em cima do resultado:

O mesmo vale para construtores com parent::__construct(...), que a página sobre construtores explica, incluindo o que acontece quando você o esquece.

protected ou private em classes filhas

Um membro protected fica escondido do código de fora, mas visível para todas as classes da família. Um membro private só é visível na classe que o declara, então uma classe filha não o enxerga:

isset($this->pin) é falso na filha porque ela não tem acesso ao $pin privado da classe pai, enquanto o próprio método hasPin() da classe pai ainda o lê. Use protected para o que as subclasses devem usar como base, e private para detalhes que você quer poder mudar livremente.

Polimorfismo e instanceof

Código escrito para o tipo da classe pai funciona com todas as filhas. Cada objeto executa a própria versão de um método sobrescrito, então um único loop trata todos eles. instanceof verifica se um objeto é de uma classe ou de qualquer uma das filhas dela:

Quando a classe pai nunca deve ser usada sozinha (um Shape simples com área 0 faz pouco sentido), torne-a uma classe abstrata e declare area() como abstrato.

Regras de sobrescrita: as assinaturas precisam continuar compatíveis

Um método que sobrescreve precisa aceitar pelo menos o que o da classe pai aceitava e retornar algo que quem chama a classe pai consiga usar. Você pode adicionar um parâmetro opcional, ampliar o tipo de um parâmetro ou restringir o tipo de retorno; não pode adicionar um parâmetro obrigatório nem tornar privado um método público.

Troque string $sep = ',' por um string $sep obrigatório e o PHP se recusa a compilar a classe com um erro fatal ("Declaration of CsvExporter::export(array rows,stringrows, string sep): string must be compatible with Exporter::export(array $rows): string").

Classes e métodos final

final interrompe a herança naquele ponto. Um método final não pode ser sobrescrito, e uma final class não pode ser estendida. As duas regras são verificadas quando o arquivo é compilado, então o script nem começa:

<?php
class Payment
{
    final public function charge(int $cents): string
    {
        return "charged $cents";
    }
}

class FreePayment extends Payment
{
    public function charge(int $cents): string
    {
        return 'free';
    }
}
PHP Fatal error:  Cannot override final method Payment::charge() in /home/index.php on line 12

Para uma classe final, a mensagem é Class B cannot extend final class A. Marque um método como final quando a classe pai depende de ele se comportar de um único jeito, por exemplo um método que verifica permissões antes de fazer qualquer outra coisa.

A armadilha dos métodos privados

Um método privado não é herdado, então um método da filha com o mesmo nome não o sobrescreve. O código da classe pai continua chamando a própria versão privada, o que surpreende quem espera que o método da filha rode:

greet() ainda imprime Hello: o $this->word() da classe pai aponta para o método privado da classe pai. Troque private por protected em Greeter e rode de novo; agora o método da filha é uma sobrescrita de verdade e greet() diz Bonjour.

Perguntas frequentes

Como funciona o extends no PHP?

class Dog extends Animal torna Dog filha de Animal. Um objeto Dog tem todas as propriedades e métodos public e protected de Animal, pode adicionar os próprios e pode substituir (sobrescrever) métodos herdados declarando um método com o mesmo nome.

Como chamo o método da classe pai no PHP?

Use parent::methodName() dentro do método da filha, por exemplo return parent::describe() . ' and more';. Para o construtor, é parent::__construct(...).

O PHP suporta herança múltipla?

Não. Uma classe só pode estender uma classe pai. Para compartilhar comportamento de várias fontes, implemente várias interfaces (class A implements B, C) e use traits (use Loggable, Timestamps;).

O que significa final no PHP?

Um método final não pode ser sobrescrito por uma classe filha, e uma final class não pode ser estendida. Violar qualquer uma das regras é um erro fatal quando a classe é compilada, por exemplo Cannot override final method A::f().

Uma classe filha pode acessar uma propriedade privada da classe pai no PHP?

Não. Um membro private pertence só à classe que o declara, então na filha $this->pin é uma propriedade indefinida (um aviso, depois null) e um método da filha com o mesmo nome não sobrescreve um privado. Declare o membro como protected quando as classes filhas precisarem dele.

Ilustração das linguagens de programação do Coddy

Aprenda a programar com o Coddy

COMEÇAR