Usando Múltiplos Traits
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 52 de 91.
Uma única trait é útil, mas o verdadeiro poder surge quando você combina múltiplas traits em uma única classe. O PHP permite que você inclua quantas traits precisar, dando à sua classe capacidades de várias fontes ao mesmo tempo.
Para usar múltiplos traits, basta listá-los separados por vírgulas após a palavra-chave use:
<?php
trait Timestampable {
public function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
trait Identifiable {
private string $id;
public function generateId(): void {
$this->id = uniqid('id_');
}
public function getId(): string {
return $this->id;
}
}
class Post {
use Timestampable, Identifiable;
public function __construct(public string $title) {
$this->generateId();
}
}
$post = new Post("Hello World");
echo $post->getId() . " - " . $post->getTimestamp();
Saída:
id_6789abc123 - 2024-01-15 10:30:00A classe Post agora possui métodos de ambos os traits. Cada trait contribui com sua própria funcionalidade - Timestampable fornece métodos relacionados ao tempo, enquanto Identifiable lida com IDs únicos. Essa abordagem mantém cada trait focado em uma única responsabilidade, tornando seu código mais modular e reutilizável.
O que acontece quando duas traits têm métodos com o mesmo nome? Essa é uma situação de conflito que exploraremos na próxima lição.
Desafio
FácilVamos construir um sistema de gerenciamento de produtos que combina múltiplos traits para dar aos produtos capacidades de precificação e de inventário. Cada trait lidará com uma única responsabilidade, e sua classe de produto ganhará funcionalidades de ambos.
Você organizará seu código em três arquivos:
Priceable.php— Crie um trait chamadoPriceableque lida com a funcionalidade de precificação. O trait deve ter:- Uma propriedade privada
$price(float) - Um método
setPrice(float $price)que armazena o preço - Um método
getPrice()que retorna o preço - Um método
getFormattedPrice()que retorna o preço formatado como"$[price]"com 2 casas decimais
- Uma propriedade privada
Stockable.php— Crie um trait chamadoStockableque gerencia o inventário. O trait deve ter:- Uma propriedade privada
$stock(integer) - Um método
setStock(int $quantity)que armazena a quantidade em estoque - Um método
getStock()que retorna o estoque atual - Um método
isInStock()que retornatruese o estoque for maior que 0, efalsecaso contrário
- Uma propriedade privada
main.php— Inclua ambos os arquivos de trait e crie uma classeProductque utiliza os traitsPriceableeStockable. Use a promoção de construtor para definir uma propriedade pública$name. O construtor também deve aceitar um preço e uma quantidade em estoque, usando os métodos dos traits para defini-los.Você receberá três entradas: um nome de produto, um preço e uma quantidade em estoque. Crie um produto com esses valores e imprima quatro linhas:
- O nome do produto
- O preço formatado (usando
getFormattedPrice()) - A quantidade em estoque
"Available"se estiver em estoque, ou"Out of stock"caso contrário
Isso demonstra como múltiplos traits trabalham juntos — sua classe Product ganha capacidades de precificação de um trait e gerenciamento de inventário de outro, mantendo cada responsabilidade nitidamente separada enquanto as combina em um produto com todos os recursos.
Folha de consulta
Para usar múltiplas traits em uma classe, liste-as separadas por vírgulas após a palavra-chave use:
<?php
trait Timestampable {
public function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
trait Identifiable {
private string $id;
public function generateId(): void {
$this->id = uniqid('id_');
}
public function getId(): string {
return $this->id;
}
}
class Post {
use Timestampable, Identifiable;
public function __construct(public string $title) {
$this->generateId();
}
}
$post = new Post("Hello World");
echo $post->getId() . " - " . $post->getTimestamp();
// Saída: id_6789abc123 - 2024-01-15 10:30:00
Cada trait contribui com sua própria funcionalidade para a classe. Essa abordagem mantém cada trait focada em uma única responsabilidade, tornando o código mais modular e reutilizável.
Experimente você mesmo
<?php
require_once 'Priceable.php';
require_once 'Stockable.php';
// TODO: Crie uma classe Product que use as traits Priceable e Stockable
// Use a promoção de construtor para a propriedade pública $name
// O construtor deve aceitar name, price e stock, e usar métodos das traits para definir price e stock
class Product {
// TODO: Use as traits aqui
// TODO: Implemente o construtor com promoção de construtor para $name
// e defina o preço e o estoque usando os métodos das traits
}
// Ler entrada
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$stock = intval(trim(fgets(STDIN)));
// TODO: Crie uma instância de Product com os valores de entrada
// TODO: Imprima o nome do produto
// TODO: Imprima o preço formatado usando getFormattedPrice()
// TODO: Imprima a quantidade em estoque
// TODO: Imprima "Available" se estiver em estoque, ou "Out of stock" se não estiver
?>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