Projeto Prático de OOP
Você já estudou cinco lições sobre programação orientada a objetos. Agora, vamos unir todo esse conhecimento em dois projetos: um sistema completo de usuários que abrange herança, enums, traits e interfaces, e uma estrutura simples que lhe dará uma primeira noção da arquitetura MVC.
1. Projeto Um: Sistema de Gerenciamento de Funções do Usuário
Combine classes, herança, enums, traits e interfaces para criar uma estrutura completa de gerenciamento de funções de usuário.
▶ Exemplo: Sistema de usuários totalmente baseado em OOP
<?php
// === Enums ===
enum UserRole: string {
case ADMIN = 'admin';
case EDITOR = 'editor';
case MEMBER = 'member';
case GUEST = 'guest';
}
enum UserStatus: string {
case ACTIVE = 'active';
case INACTIVE = 'inactive';
case BANNED = 'banned';
}
// === Interfaces ===
interface Loggable {
public function getLogIdentifier(): string;
}
interface Manageable {
public function canAccess(string $resource): bool;
public function getPermissions(): array;
}
// === Traits ===
trait HasTimestamps {
public readonly string $createdAt;
public readonly string $updatedAt;
public function touch(): void {
$now = date("Y-m-d H:i:s");
if (!isset($this->createdAt)) {
$this->createdAt = $now;
}
$this->updatedAt = $now;
}
}
trait ArraySerializable {
public function toArray(): array {
return get_object_vars($this);
}
}
// === Base Class ===
abstract class User implements Loggable, Manageable {
use HasTimestamps, ArraySerializable;
public function __construct(
public readonly string $id,
public string $name,
public string $email,
public UserRole $role = UserRole::MEMBER,
public UserStatus $status = UserStatus::ACTIVE,
) {
$this->touch();
}
public function getLogIdentifier(): string {
return "User#{$this->id} ({$this->name})";
}
abstract public function canAccess(string $resource): bool;
abstract public function getPermissions(): array;
abstract public function getRoleLabel(): string;
}
// === Concrete Role Classes ===
class Admin extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::ADMIN);
}
public function canAccess(string $resource): bool {
return true; // Admin can access everything
}
public function getPermissions(): array {
return ['create', 'read', 'update', 'delete', 'manage_users', 'system_config'];
}
public function getRoleLabel(): string {
return '🔧 Admin';
}
}
class Editor extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::EDITOR);
}
public function canAccess(string $resource): bool {
return in_array($resource, ['articles', 'media', 'comments']);
}
public function getPermissions(): array {
return ['create', 'read', 'update', 'manage_comments'];
}
public function getRoleLabel(): string {
return '✏️ Editor';
}
}
class Member extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::MEMBER);
}
public function canAccess(string $resource): bool {
return in_array($resource, ['articles', 'comments', 'profile']);
}
public function getPermissions(): array {
return ['read', 'comment'];
}
public function getRoleLabel(): string {
return '👤 Member';
}
}
// === Access Manager ===
class AccessManager {
public function checkAccess(User $user, string $resource): string {
if ($user->status === UserStatus::BANNED) {
return "{$user->getRoleLabel()} {$user->name}: Banned, access denied for {$resource}";
}
$allowed = $user->canAccess($resource)
? "✅ Access Granted" : "❌ Access Denied";
return "{$user->getRoleLabel()} {$user->name}: {$allowed} {$resource}";
}
public function listAllAccess(array $users, array $resources): void {
foreach ($users as $user) {
echo "<h4>{$user->getLogIdentifier()}</h4>";
echo "Permissions: " . implode(', ', $user->getPermissions()) . "<br>";
foreach ($resources as $res) {
echo $this->checkAccess($user, $res) . "<br>";
}
}
}
}
// === Test the System ===
$users = [
new Admin("u1", "John", "admin@example.com"),
new Editor("u2", "Jane", "editor@example.com"),
new Member("u3", "Bob", "member@example.com"),
];
$resources = ['articles', 'media', 'comments', 'system_config', 'manage_users'];
$manager = new AccessManager();
$manager->listAllAccess($users, $resources);
// Test enum + serialization
echo "<br>Admin data: " . json_encode($users[0]->toArray(), JSON_UNESCAPED_UNICODE);
?>
2. Projeto 2: Framework MVC simples
Compreenda o conceito MVC de Router, Controller e View — essa é a ideia central por trás de frameworks como o Laravel.
▶ Exemplo: Mini MVC
<?php
// === Router ===
class Router {
private array $routes = [];
public function get(string $path, callable $handler): void {
$this->routes['GET'][$path] = $handler;
}
public function post(string $path, callable $handler): void {
$this->routes['POST'][$path] = $handler;
}
public function dispatch(string $method, string $uri): void {
$path = parse_url($uri, PHP_URL_PATH);
$handler = $this->routes[$method][$path] ?? null;
if ($handler) {
echo $handler($_GET);
} else {
http_response_code(404);
echo "<h2>404 — Page Not Found</h2>";
}
}
}
// === View Base ===
class View {
public static function render(string $template, array $data = []): string {
extract($data);
ob_start();
include __DIR__ . "/{$template}.php";
return ob_get_clean();
}
}
// === Controller Base ===
abstract class Controller {
protected function json(array $data, int $code = 200): void {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
}
}
// === Concrete Controller ===
class HomeController extends Controller {
public function index(): void {
echo View::render('home', [
'title' => 'Home',
'message' => 'Welcome to my blog!',
]);
}
public function about(): void {
echo View::render('about', [
'title' => 'About Us',
'team' => ['John', 'Jane', 'Bob'],
'version' => '1.0.0',
]);
}
public function api(): void {
$this->json([
'status' => 'ok',
'data' => ['version' => '1.0.0', 'uptime' => time()],
]);
}
}
// === Set Up Routes ===
$router = new Router();
$home = new HomeController();
$router->get('/', fn() => $home->index());
$router->get('/about', fn() => $home->about());
$router->get('/api/status', fn() => $home->api());
// === Launch the App ===
$router->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
?>
O arquivo de visualização anexo home.php:
<!DOCTYPE html>
<html lang="en">
<head><title><?= $title ?></title></head>
<body>
<h1><?= $message ?></h1>
<p>This page is built using MVC principles.</p>
</body>
</html>
3. A mudança de mentalidade: da programação procedural à OOP
| Pensamento procedural | Pensamento OOP |
|---|---|
“Preciso ler os dados do usuário” → escreva uma função getUser() |
“O que é um usuário? Quais são suas propriedades e comportamentos?” → projete uma classe User |
| Dados e funções espalhados por vários arquivos | Dados + comportamento encapsulados em uma classe |
| Código duplicado → copiar e colar ou extrair uma função | Código duplicado → usar herança ou Traits |
Passar strings 'admin' para permissões |
Passar enumeração UserRole::ADMIN, com segurança de tipos |
if ($role === 'admin')).
❓ Perguntas Frequentes
P: O que um Controlador realmente faz no MVC? R: O Controlador é o “diretor de tráfego” — ele recebe a solicitação, chama o Modelo para obter dados e escolhe a Visualização para renderização. Ele não lida com a lógica de negócios propriamente dita (essa é a função do Modelo) e não gera código HTML (essa é a função da Visualização).
P: Devo criar meu próprio framework ou usar um já existente? R: Crie um mini-framework durante a fase de aprendizado para entender os princípios (assim como nesta lição). Use o Laravel/Symfony para produção. Depois de criar seu próprio Router/Controller/View uma vez, usar o Laravel faz você pensar: “Ah, então é isso que acontece nos bastidores.”
❓ Perguntas Frequentes
P: Como faço para testar a mini-framework MVC que criei? R: Inicie o Apache ou o servidor PHP integrado (php -S localhost:8000) e acesse http://localhost:8000 no seu navegador. O despachador direciona para o controlador apropriado com base na URL. Use var_dump() ou error_log() para depurar passo a passo.
📖 Resumo
- O sistema do usuário combina todos os cinco principais mecanismos da Programação Orientada a Objetos (OOP): enums, herança, interfaces, traits e polimorfismo
abstract class Userdefine o modelo do usuário; as subclasses implementam recursos específicos da funçãoAccessManagerutiliza o polimorfismo para verificar de maneira uniforme as permissões entre diferentes funções- Princípio MVC: o roteador encaminha as solicitações → o controlador coordena → a visualização renderiza
- A programação orientada a objetos (OOP) não é uma solução milagrosa — considere utilizá-la quando seu código ultrapassar 500 linhas, apresentar lógica repetitiva ou depender de variáveis globais
📝 Exercícios
- Com base no sistema do usuário, adicione uma função
Guest(que só permite acessar artigos, sem nenhuma permissão de edição) e inclua-a no conjunto de testes. - Adicione um método
addRoute('GET/POST', $path, $handler)ao roteador para que uma única chamada possa registrar ambos os métodos. - Adicione um
UserControllerà estrutura MVC que implemente uma lista de usuários (lida a partir de um array) e uma página de detalhes do usuário (consulta por ID).



