Desafio PHP

Trait com método abstrato e validação

Enunciado

Crie uma trait Validavel com um método abstrato regras(): array e um método concreto validar(array $dados): bool que retorna false se algum campo obrigatório estiver vazio, e true caso contrário. Crie duas classes: Usuario e Produto, cada uma usando a trait e implementando regras() com campos diferentes. Teste com dados válidos e inválidos para cada classe.

Requisitos

  • A trait Validavel deve ter abstract public function regras(): array;.
  • O método validar deve percorrer as regras e retornar false se um campo 'required' estiver vazio.
  • As classes Usuario e Produto devem usar a trait e implementar regras().
  • A saída deve mostrar true ou false para cada teste, conforme os dados.

Código inicial

<?php
// Defina a trait Validavel e as classes Usuario e Produto

$u = new Usuario();
var_dump($u->validar(['nome' => 'Ana', 'email' => 'a@b.com']));
var_dump($u->validar(['nome' => '', 'email' => 'a@b.com']));

$p = new Produto();
var_dump($p->validar(['titulo' => 'Livro', 'preco' => 10]));
var_dump($p->validar(['titulo' => '', 'preco' => 10]));

Saída esperada

bool(true)
bool(false)
bool(true)
bool(false)
Ver dica

No método validar, use $this->regras() para obter o array e verifique empty($dados[$campo]) quando a regra for 'required'.

Mostrar solução
<?php
trait Validavel {
    // Método abstrato: obriga a classe a definir as regras
    abstract public function regras(): array;

    public function validar(array $dados): bool {
        foreach ($this->regras() as $campo => $regra) {
            if ($regra === 'required' && empty($dados[$campo])) {
                return false;
            }
        }
        return true;
    }
}

class Usuario {
    use Validavel;

    public function regras(): array {
        return ['nome' => 'required', 'email' => 'required'];
    }
}

class Produto {
    use Validavel;

    public function regras(): array {
        return ['titulo' => 'required', 'preco' => 'required'];
    }
}

$u = new Usuario();
var_dump($u->validar(['nome' => 'Ana', 'email' => 'a@b.com']));
var_dump($u->validar(['nome' => '', 'email' => 'a@b.com']));

$p = new Produto();
var_dump($p->validar(['titulo' => 'Livro', 'preco' => 10]));
var_dump($p->validar(['titulo' => '', 'preco' => 10]));

Passo a passo

  1. A trait Validavel declara abstract public function regras(): array;. Isso força qualquer classe que use a trait a implementar regras().
  2. O método concreto validar() percorre o array retornado por $this->regras().
  3. Para cada campo, se a regra for 'required' e o valor em $dados estiver vazio (empty), retorna false imediatamente.
  4. Se o loop terminar sem falhas, retorna true.
  5. Usuario usa a trait e define regras() com nome e email obrigatórios.
  6. Produto usa a trait e define regras() com titulo e preco obrigatórios.
  7. Os testes chamam validar() com dados válidos e inválidos, imprimindo bool(true) ou bool(false) via var_dump.

Por que funciona

A trait fornece a lógica de validação reutilizável, mas delega à classe a definição das regras específicas através do método abstrato. Isso combina reuso de código com polimorfismo: cada classe mantém sua particularidade sem duplicar o algoritmo de validação. É um exemplo clássico de trait com contrato.

Erros comuns

  • Não implementar regras() na classe: erro fatal "Class Usuario contains 1 abstract method...".
  • Usar isset em vez de empty: isset retorna true para string vazia, então a validação falharia. Use empty.
  • Esquecer o use Validavel; na classe: o método validar não existirá.

Outra forma de resolver

Em vez de método abstrato, a trait poderia acessar uma propriedade $regras definida na classe. Porém, o método abstrato é mais seguro, pois o PHP garante em tempo de compilação que a classe implementou o contrato.

Saída esperada

bool(true)
bool(false)
bool(true)
bool(false)