Métodos Abstratos em Traits
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy. Lição 54 de 91.
Traits podem fornecer métodos prontos para uso, mas às vezes você precisa que a classe que usa o trait implemente uma funcionalidade específica. É aí que os métodos abstratos em traits se tornam úteis — eles definem um contrato que a classe que os utiliza deve cumprir.
Quando um trait declara um método abstrato, qualquer classe que use esse trait deve implementá-lo:
<?php
trait Notifiable {
abstract public function getEmail(): string;
public function sendNotification(string $message): void {
echo "Sending to " . $this->getEmail() . ": $message";
}
}
class User {
use Notifiable;
public function __construct(private string $email) {}
public function getEmail(): string {
return $this->email;
}
}
$user = new User("john@example.com");
$user->sendNotification("Welcome!");
Saída:
Sending to john@example.com: Welcome!A trait fornece o método sendNotification(), mas depende da implementação de getEmail() pela classe. Isso cria um padrão poderoso no qual a trait lida com a lógica comum enquanto delega os detalhes específicos da classe à classe que a implementa.
Se uma classe usar o trait sem implementar o método abstrato, o PHP emitirá um erro fatal. Isso garante que os traits possam depender com segurança da existência de determinados métodos, tornando seu código mais previsível e fácil de manter.
Desafio
FácilVamos criar um sistema de preços em que diferentes tipos de produtos calculam seus preços finais de maneiras diferentes, mas todos compartilham uma lógica de desconto comum por meio de um trait com um método abstrato.
Você organizará seu código em três arquivos:
Discountable.php: crie um trait chamadoDiscountableque forneça a funcionalidade de desconto. O trait deve ter:- Um método abstrato
getBasePrice(): floatque as classes que usam esse trait devem implementar - Um método
applyDiscount(int $percent)que calcula e retorna o preço após aplicar a porcentagem de desconto ao preço base - Um método
getFinalPrice(int $percent)que retorna uma string formatada:"Final price: $[discounted_price]"com 2 casas decimais
- Um método abstrato
Product.php: crie uma classeProductque use o traitDiscountable. Inclua o arquivo do trait. Use a promoção de construtor para definir um$nameprivado (string) e um$priceprivado (float). Implemente o método obrigatóriogetBasePrice()para retornar o preço do produto.main.php: inclua o arquivo Product. Você receberá três entradas: um nome de produto, um preço e uma porcentagem de desconto. Crie uma instância deProducte imprima duas linhas:- O preço base formatado como
"Base: $[price]"com 2 casas decimais - O resultado da chamada de
getFinalPrice()com a porcentagem de desconto
- O preço base formatado como
Esse padrão é poderoso porque o trait Discountable pode ser usado por qualquer classe — produtos, serviços, assinaturas — desde que implementem getBasePrice(). O trait fornece a lógica de desconto compartilhada, enquanto cada classe define de onde vem seu preço base.
Experimente você mesmo
<?php
require_once 'Product.php';
// Ler entradas
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));
// TODO: Crie uma instância de Product com o nome e o preço
// TODO: Imprima o preço base formatado como "Base: $[price]" com 2 casas decimais
// TODO: Imprima o resultado de chamar getFinalPrice() com a porcentagem de desconto
?>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 OOP
Arquivos externosIntrodução à OOPClasses vs. objetosA palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodosA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em ProfundidadeGetters e SettersOcultação de InformaçõesPromoção de Construtor (8.0)Recapitulação - Sistema de Registros de Alunos10Conceitos Avançados de OOP
Composição vs. HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibras (PHP 8.1)Análise Profunda da 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 às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataTipagem 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 NulosTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadaTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários3Propriedades de Classes
Propriedades de Instância vs. EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Somente para Leitura (PHP 8.1)Recapitulação - Gerenciador de Contas Bancárias6Polimorfismo
Revisão da Sobrescrita de MétodosPolimorfismo via InterfacesIndicação de Tipos e Tipos UnionVinculação Estática TardiaRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos entre 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 StrategyPratique por conta própria: Compilador de PHP online