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 utiliza a trait implemente funcionalidades específicas. É aqui que os métodos abstratos em traits se tornam úteis - eles definem um contrato que a classe que as utiliza deve cumprir.
Quando uma trait declara um método abstrato, qualquer classe que utilize essa 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 que o getEmail() seja implementado pela classe. Isso cria um padrão poderoso onde a trait lida com a lógica comum enquanto delega detalhes específicos da classe para a classe que a implementa.
Se uma classe usa a trait sem implementar o método abstrato, o PHP lança um erro fatal. Isso garante que as traits possam depender com segurança da existência de certos métodos, tornando seu código mais previsível e fácil de manter.
Desafio
FácilVamos construir um sistema de precificação onde diferentes tipos de produtos calculam seus preços finais de forma distinta, mas todos compartilham uma lógica de desconto comum através de uma trait com um método abstrato.
Você organizará seu código em três arquivos:
Discountable.php— Crie uma trait chamadaDiscountableque fornece funcionalidade de desconto. A trait deve ter:- Um método abstrato
getBasePrice(): floatque as classes que utilizam esta 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 utiliza a traitDiscountable. Inclua o arquivo da trait. Use a promoção de construtor para definir um$name(string) privado e um$price(float) privado. Implemente o métodogetBasePrice()obrigatório 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
Este padrão é poderoso porque a trait Discountable pode ser usada por qualquer classe — produtos, serviços, assinaturas — desde que implementem getBasePrice(). A trait fornece a lógica de desconto compartilhada, enquanto cada classe define de onde vem seu preço base.
Folha de consulta
Traits podem declarar métodos abstratos que devem ser implementados por qualquer classe que utilize a trait:
<?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;
}
}
A trait fornece métodos prontos para uso, ao mesmo tempo em que exige que a classe implemente funcionalidades específicas. Se uma classe usar a trait sem implementar o método abstrato, o PHP lançará um erro fatal.
Este padrão permite que as traits lidem com a lógica comum enquanto delegam detalhes específicos da classe para a classe que a implementa.
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: Criar uma instância de Product com o nome e o preço
// TODO: Imprimir o preço base formatado como "Base: $[price]" com 2 casas decimais
// TODO: Imprimir o resultado da chamada de 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 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