Desafio PHP
Sistema de carrinho de compras
Enunciado
Crie uma classe Produto com propriedades nome (string) e preco (float) usando promoção de construtor. Crie uma classe Carrinho que mantém um array de produtos. O Carrinho deve ter métodos adicionarProduto(Produto $produto), removerProduto(string $nome) e total(): float. O método removerProduto deve remover o primeiro produto com o nome especificado. Exiba o total antes e depois de remover um produto.
Requisitos
- A classe
Produtodeve usar promoção de construtor paranomeepreco. - A classe
Carrinhodeve ter uma propriedade privada$produtosinicializada como array vazio. adicionarProdutoadiciona um objetoProdutoao array.removerProdutoremove o primeiro produto com o nome fornecido, se existir.totalretorna a soma dos preços de todos os produtos no carrinho.
Código inicial
<?php
// Defina a classe Produto com promoção de construtor
// Defina a classe Carrinho
// Crie produtos, adicione ao carrinho, remova um e mostre os totais
Saída esperada
Total antes: 45.90
Total depois: 30.00
Ver dica
Para remover, percorra o array com foreach e use unset($this->produtos[$indice]) ou array_splice. Lembre-se de reindexar se necessário.
Mostrar solução
<?php
class Produto {
public function __construct(
private string $nome,
private float $preco
) {}
public function getNome(): string {
return $this->nome;
}
public function getPreco(): float {
return $this->preco;
}
}
class Carrinho {
private array $produtos = [];
public function adicionarProduto(Produto $produto): void {
$this->produtos[] = $produto;
}
public function removerProduto(string $nome): void {
foreach ($this->produtos as $indice => $produto) {
if ($produto->getNome() === $nome) {
unset($this->produtos[$indice]);
// Reindexar o array para evitar lacunas
$this->produtos = array_values($this->produtos);
break; // remove apenas o primeiro
}
}
}
public function total(): float {
$soma = 0.0;
foreach ($this->produtos as $produto) {
$soma += $produto->getPreco();
}
return $soma;
}
}
// Criando produtos
$p1 = new Produto("Camiseta", 29.90);
$p2 = new Produto("Caneta", 5.00);
$p3 = new Produto("Caderno", 11.00);
$carrinho = new Carrinho();
$carrinho->adicionarProduto($p1);
$carrinho->adicionarProduto($p2);
$carrinho->adicionarProduto($p3);
echo "Total antes: " . number_format($carrinho->total(), 2, '.', '') . PHP_EOL;
$carrinho->removerProduto("Caneta");
echo "Total depois: " . number_format($carrinho->total(), 2, '.', '') . PHP_EOL;
Passo a passo
- A classe
Produtousa promoção de construtor para criar as propriedades privadas$nomee$preco, e fornece getters públicos. - A classe
Carrinhotem a propriedade$produtosinicializada como array vazio. adicionarProdutoinsere o objetoProdutono final do array com[].removerProdutopercorre o array; ao encontrar o primeiro produto com o nome desejado, remove comunsete reindexa comarray_values.totalpercorre os produtos e soma os preços usando o gettergetPreco().- No script principal, criamos três produtos, adicionamos ao carrinho, mostramos o total, removemos a caneta e mostramos o novo total.
Por que funciona
A composição (Carrinho contém Produtos) demonstra como objetos podem interagir. O uso de $this->produtos mantém o estado do carrinho. A reindexação após unset evita problemas em iterações futuras e mantém o array como lista.
Erros comuns
- Não reindexar após
unset: o array fica com lacunas, masforeachainda funciona; porém, se usarforcom índices, pode falhar. - Comparar nomes com
==em vez de===: pode causar coerção de tipos indesejada. - Esquecer de inicializar
$produtoscomo array:private array $produtos;sem valor padrão causaria erro ao adicionar. - Remover todos os produtos com o mesmo nome em vez do primeiro: o
breakgarante que apenas o primeiro seja removido.
Outra forma de resolver
Usar array_filter para remover por nome, mas isso removeria todas as ocorrências. Para remover apenas a primeira, pode-se usar array_search com array_splice:
$nomes = array_map(fn($p) => $p->getNome(), $this->produtos);
$indice = array_search($nome, $nomes, true);
if ($indice !== false) {
array_splice($this->produtos, $indice, 1);
}
Essa abordagem é mais concisa e evita reindexação manual.
Saída esperada
Total antes: 45.90
Total depois: 30.00