Menu
Coddy logo textTech

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.

challenge icon

Desafio

Fácil

Vamos 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 chamada Discountable que fornece funcionalidade de desconto. A trait deve ter:
    • Um método abstrato getBasePrice(): float que 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
    A trait lida com todo o cálculo de desconto, mas depende de cada classe para informar qual é o preço base.
  • Product.php — Crie uma classe Product que utiliza a trait Discountable. 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étodo getBasePrice() 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 de Product e 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

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

?>
quiz iconTeste seus conhecimentos

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