Sobrescrita de Métodos Revisitada
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 33 de 91.
Você já aprendeu sobre a sobrescrita de métodos no capítulo de Herança. Agora vamos explorar como isso se conecta ao polimorfismo - um dos conceitos mais poderosos da programação orientada a objetos.
Polimorfismo significa "muitas formas". Quando você sobrescreve um método em uma classe filha, você está dando a esse método uma forma diferente, mantendo o mesmo nome. A mágica acontece quando você trabalha com objetos por meio de seu tipo pai:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()) . "\n";
echo makeAnimalSpeak(new Cat());
Saída:
Woof!
Meow!A função makeAnimalSpeak() aceita qualquer Animal. Ela não sabe nem se importa se recebe um Dog ou Cat. O PHP chama automaticamente o método sobrescrito correto com base no tipo real do objeto em tempo de execução.
Isso é polimorfismo em ação.
Esta abordagem permite que você escreva código flexível que funciona com uma família de objetos relacionados sem conhecer seus tipos específicos. Você pode adicionar novas classes de animais mais tarde, e a função funcionará com elas automaticamente.
Ponto Chave: A sobrescrita de método habilita o polimorfismo ao permitir que diferentes classes respondam de forma diferente à mesma chamada de método, determinada em tempo de execução pelo tipo real do objeto.
Desafio
FácilVamos construir um sistema de instrumentos musicais que demonstra polimorfismo através da sobrescrita de métodos. Você criará uma classe base Instrument e duas classes filhas que produzem, cada uma, seu próprio som único — depois, usará uma única função para tocar qualquer instrumento de forma polimórfica.
Você organizará seu código em quatro arquivos:
Instrument.php— Crie uma classeInstrumentcom uma propriedade protegida$namedefinida através do construtor. Adicione um métodoplay()que retorna"[name] makes a sound". Isso serve como o comportamento base que as classes filhas irão sobrescrever.Guitar.php— Crie uma classeGuitarque estendeInstrument. Inclua o arquivo pai. O construtor aceita o nome e o passa para o construtor pai. Sobrescreva o métodoplay()para retornar"[name] strums a chord".Drum.php— Crie uma classeDrumque estendeInstrument. Inclua o arquivo pai. O construtor aceita o nome e o passa para o construtor pai. Sobrescreva o métodoplay()para retornar"[name] beats a rhythm".main.php— Inclua os arquivos Guitar e Drum. Crie uma função chamadaperformWithque aceita um parâmetroInstrument(com type-hint) e retorna o resultado da chamada deplay()nele. Esta função demonstra o polimorfismo — ela funciona com qualquer tipo de instrumento através do type hint da classe pai.
Você receberá duas entradas: um nome para a guitarra e um nome para o tambor. Crie um Guitar e um Drum com esses nomes. Passe cada um para sua função performWith() e imprima os resultados — a guitarra primeiro, depois o tambor, cada um em sua própria linha.
Observe como performWith() aceita qualquer Instrument, mas o PHP chama automaticamente o método play() sobrescrito correto com base no tipo real do objeto em tempo de execução. Isso é o polimorfismo em ação!
Folha de consulta
Polimorfismo significa "muitas formas" e permite que objetos de diferentes classes sejam tratados por meio de seu tipo pai, mantendo seu comportamento específico.
Quando você sobrescreve um método em classes filhas, o PHP chama automaticamente a versão correta com base no tipo real do objeto em tempo de execução:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()); // Woof!
echo makeAnimalSpeak(new Cat()); // Meow!
A função makeAnimalSpeak() aceita qualquer tipo Animal por meio de seu "type hint" de parâmetro. Ela não precisa conhecer a classe específica - o PHP determina qual método sobrescrito chamar em tempo de execução com base no tipo real do objeto.
Isso permite um código flexível que funciona com uma família de objetos relacionados sem conhecer seus tipos específicos. Novas classes filhas podem ser adicionadas posteriormente e funcionarão automaticamente com as funções existentes.
Experimente você mesmo
<?php
// Inclua os arquivos de instrumentos
require_once 'Guitar.php';
require_once 'Drum.php';
// Leia a entrada
$guitarName = trim(fgets(STDIN));
$drumName = trim(fgets(STDIN));
// TODO: Crie uma função chamada performWith que:
// - Aceite um parâmetro Instrument (use o type hint: Instrument $instrument)
// - Retorne o resultado da chamada de play() no instrumento
// TODO: Crie um Guitar com $guitarName e um Drum com $drumName
// TODO: Passe cada um para performWith() e imprima os resultados (guitarra primeiro, depois bateria)
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodoA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em DetalhesGetters e SettersOcultação de InformaçãoPromoção de Construtor (8.0)Recapitulação - Sistema de Registro de Alunos10Conceitos Avançados de POO
Composição vs HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibers (PHP 8.1)Mergulho Profundo em Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA Palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto Organizado5Interfaces e Contratos
Introdução a InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataType Hinting com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos AnuláveisTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadasTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário3Propriedades de Classe
Propriedades de Instância vs EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Readonly (PHP 8.1)Recapitulação - Gerenciador de Conta Bancária6Polimorfismo
Sobrescrita de Métodos RevisitadaPolimorfismo via InterfacesType Hinting e Union TypesLate Static BindingRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos de TraitsMétodos Abstratos em TraitsTraits vs Herança12Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy