Desafio PHP
Organização com Composer e PSR-4
Enunciado
Configure um projeto Composer com autoload PSR-4 para o namespace App\ apontando para src/. Crie as classes App\Models\Product, App\Repositories\ProductRepository e App\Services\ProductService. O ProductRepository deve armazenar produtos em um array e ter métodos add(Product $product) e all(): array. O ProductService deve receber o repositório no construtor e ter um método listNames(): array que retorna os nomes dos produtos. No arquivo principal, instancie tudo, adicione dois produtos e exiba a lista de nomes separados por vírgula.
Requisitos
- O
composer.jsondefineautoload.psr-4comApp\\mapeado parasrc/. - As classes estão nos namespaces e diretórios corretos.
- O
ProductServicedepende doProductRepositoryvia injeção no construtor. - O programa principal usa o autoload do Composer (via
vendor/autoload.php).
Código inicial
<?php
// Configure o composer.json, crie as classes e o arquivo principal
Saída esperada
Notebook, Mouse
Ver dica
Após criar o composer.json, execute composer dump-autoload para gerar o autoloader. No código, use require 'vendor/autoload.php';.
Mostrar solução
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
<?php
// src/Models/Product.php
namespace App\Models;
class Product
{
public function __construct(private string $name) {}
public function getName(): string
{
return $this->name;
}
}
<?php
// src/Repositories/ProductRepository.php
namespace App\Repositories;
use App\Models\Product;
class ProductRepository
{
/** @var Product[] */
private array $products = [];
public function add(Product $product): void
{
$this->products[] = $product;
}
/** @return Product[] */
public function all(): array
{
return $this->products;
}
}
<?php
// src/Services/ProductService.php
namespace App\Services;
use App\Repositories\ProductRepository;
class ProductService
{
public function __construct(private ProductRepository $repository) {}
public function listNames(): array
{
return array_map(
fn($product) => $product->getName(),
$this->repository->all()
);
}
}
<?php
// index.php
require 'vendor/autoload.php';
use App\Models\Product;
use App\Repositories\ProductRepository;
use App\Services\ProductService;
$repository = new ProductRepository();
$repository->add(new Product('Notebook'));
$repository->add(new Product('Mouse'));
$service = new ProductService($repository);
echo implode(', ', $service->listNames()) . PHP_EOL;
Passo a passo
- Criamos o
composer.jsoncom a seçãoautoload.psr-4mapeandoApp\\parasrc/. - Executamos
composer dump-autoloadpara gerar o arquivovendor/autoload.php. - A classe
Productfica emsrc/Models/Product.phpcom namespaceApp\Models. - O
ProductRepositoryarmazena produtos em um array e ofereceaddeall. - O
ProductServicerecebe o repositório via construtor e usaarray_mappara extrair os nomes. - No
index.php, incluímos o autoload do Composer e usamos as classes. - Adicionamos dois produtos, criamos o serviço e exibimos os nomes separados por vírgula.
Por que funciona
O autoload do Composer segue PSR-4: o namespace App\Models\Product é convertido para src/Models/Product.php. A injeção de dependência no ProductService desacopla as camadas, facilitando testes e manutenção.
Erros comuns
- Esquecer de rodar
composer dump-autoloadapós alterar ocomposer.json: o autoloader não é atualizado. - Colocar arquivos fora do diretório mapeado: o Composer não encontrará a classe.
- Usar
requiremanual além dovendor/autoload.php: pode causar inclusão duplicada.
Outra forma de resolver
Sem Composer, você pode implementar um autoloader manual como no exercício anterior, mas o Composer oferece vantagens como otimização e gerenciamento de dependências.
Saída esperada
Notebook, Mouse