<h2>Camada View: Templates PHP e Separação de Apresentação</h2>
<p>A camada View é responsável por toda a apresentação de dados ao usuário. Em uma arquitetura bem definida, ela não contém lógica de negócio, apenas renderização HTML. Templates PHP são arquivos que misturam marcação com variáveis PHP, permitindo dinamismos na interface. A separação entre apresentação e lógica é um princípio fundamental do padrão MVC (Model-View-Controller) que, quando bem aplicado, torna o código mais manutenível, testável e reutilizável.</p>
<p>Neste artigo, você aprenderá a estruturar templates PHP profissionais, aplicar boas práticas de separação de responsabilidades e implementar padrões reais usados em frameworks modernos.</p>
<h2>Estrutura Básica de Templates PHP</h2>
<h3>O Princípio da Separação</h3>
<p>Um template PHP deve receber dados já processados do Controller e apenas renderizá-los. Nunca deve conter consultas ao banco de dados, regras de negócio ou validações complexas. Veja um exemplo incorreto versus correto:</p>
<pre><code class="language-php"></code></pre>
<p>O segundo exemplo recebe <code>$usuarios</code> já processado pelo Controller, contendo apenas usuários válidos. Usa <code>htmlspecialchars()</code> para prevenir XSS e focam exclusivamente na renderização. Esta é a forma profissional.</p>
<h3>Estrutura de Diretórios</h3>
<pre><code>projeto/
├── app/
│ ├── Controllers/
│ │ └── UsuarioController.php
│ └── Views/
│ ├── usuarios/
│ │ ├── index.php
│ │ ├── show.php
│ │ └── form.php
│ └── layouts/
│ └── base.php
├── public/
└── config/
└── routes.php</code></pre>
<p>Este padrão permite localizar templates facilmente e escalar a aplicação. Cada recurso possui seu próprio diretório de views.</p>
<h2>Padrão Layout e Componentes Reutilizáveis</h2>
<h3>Layouts Base</h3>
<p>Templates devem herdar de um layout base que contém HTML estrutural comum, evitando duplicação:</p>
<pre><code class="language-php"><!-- app/Views/layouts/base.php -->
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= isset($titulo) ? htmlspecialchars($titulo) : 'Meu App' ?></title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<header>
<nav><!-- Menu aqui --></nav>
</header>
<main class="container">
<?= $conteudo ?>
</main>
<footer>
<p>&copy; 2024 Meu App</p>
</footer>
</body>
</html></code></pre>
<pre><code class="language-php"><!-- app/Views/usuarios/index.php -->
<div class="usuarios-list">
<h1>Usuários</h1>
<a href="/usuarios/criar" class="btn">Novo Usuário</a>
<?php if (empty($usuarios)): ?>
<p class="aviso">Nenhum usuário encontrado.</p>
<?php else: ?>
<table>
<thead>
<tr>
<th>Nome</th>
<th>Email</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
<?php foreach ($usuarios as $usuario): ?>
<tr>
<td><?= htmlspecialchars($usuario['nome']) ?></td>
<td><?= htmlspecialchars($usuario['email']) ?></td>
<td>
<a href="/usuarios/<?= (int)$usuario['id'] ?>/editar">Editar</a>
<a href="/usuarios/<?= (int)$usuario['id'] ?>/deletar">Deletar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div></code></pre>
<h3>Componentes Reutilizáveis</h3>
<p>Componentes são pequenas views incluídas em outras templates:</p>
<pre><code class="language-php"><!-- app/Views/components/alerta.php -->
<?php
$tipo = $tipo ?? 'info'; // info, sucesso, erro
$mensagem = $mensagem ?? '';
?>
<div class="alerta alerta-<?= htmlspecialchars($tipo) ?>">
<?= htmlspecialchars($mensagem) ?>
</div>
<!-- Uso em outra template -->
<?php include __DIR__ . '/../components/alerta.php';
// Variáveis $tipo e $mensagem já definidas no escopo ?></code></pre>
<h2>Integração com Controller</h2>
<h3>Renderização Profissional</h3>
<p>O Controller deve ser responsável por chamar o template e passar dados:</p>
<pre><code class="language-php"><?php
// app/Controllers/UsuarioController.php
class UsuarioController {
public function index() {
// Buscar dados (normalmente via Model)
$usuarios = [
['id' => 1, 'nome' => 'João', 'email' => 'joao@email.com'],
['id' => 2, 'nome' => 'Maria', 'email' => 'maria@email.com']
];
// Renderizar template
$this->render('usuarios/index', [
'usuarios' => $usuarios,
'titulo' => 'Lista de Usuários'
]);
}
protected function render($view, $dados = []) {
extract($dados); // Torna variáveis acessíveis
ob_start();
include __DIR__ . "/../Views/{$view}.php";
$conteudo = ob_get_clean();
include __DIR__ . '/../Views/layouts/base.php';
}
}</code></pre>
<p>A função <code>render()</code> encapsula a lógica de renderização, usando <code>ob_start()</code> para capturar a output e injetar no layout base. Isso garante consistência em toda a aplicação.</p>
<h3>Escapar Dados Sempre</h3>
<p>Sempre escape dados de user-input para prevenir XSS:</p>
<pre><code class="language-php"></code></pre>
<h2>Boas Práticas Avançadas</h2>
<h3>Uso de Variáveis de Controle</h3>
<p>Defina flags booleanas no Controller para controlar fluxos na View:</p>
<pre><code class="language-php">// No Controller
$this->render('produto/detalhes', [
'produto' => $produto,
'pode_editar' => $usuarioAutenticado && $usuarioAutenticado['id'] === $produto['usuario_id'],
'em_estoque' => $produto['quantidade'] > 0
]);
// Na View
<?php if ($pode_editar): ?>
<a href="/produtos/<?= $produto['id'] ?>/editar" class="btn">Editar</a>
<?php endif; ?>
<?php if (!$em_estoque): ?>
<span class="indisponivel">Fora de estoque</span>
<?php endif; ?></code></pre>
<h3>Evitar Lógica Complexa</h3>
<p>Se precisar formatar dados, faça no Controller usando helper functions:</p>
<pre><code class="language-php"><?php
// Helper
function formatarMoeda($valor) {
return 'R$ ' . number_format($valor, 2, ',', '.');
}
// No Controller
$dados['preco_formatado'] = formatarMoeda($produto['preco']);
// Na View (simples)
<p><?= htmlspecialchars($preco_formatado) ?></p>
?></code></pre>
<h2>Conclusão</h2>
<p>A separação entre View e lógica de negócio é fundamental para código profissional. Mantenha templates simples, delegue processamento ao Controller, sempre escape dados de entrada e reutilize componentes através de layouts. Esses princípios aumentam segurança, legibilidade e facilitam testes. Com prática, você naturalmente identificará quando código tem "cheiro" de estar no lugar errado — confie nesse instinto e refatore.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.php.net/manual/pt_BR/security.php" target="_blank" rel="noopener noreferrer">PHP Manual - Security</a></li>
<li><a href="https://www.php-fig.org/psr/psr-1/" target="_blank" rel="noopener noreferrer">PSR-1: Basic Coding Standard</a></li>
<li><a href="https://owasp.org/www-community/attacks/xss/" target="_blank" rel="noopener noreferrer">OWASP - Cross Site Scripting (XSS)</a></li>
<li><a href="https://martinfowler.com/eaaDev/uiArchs.html" target="_blank" rel="noopener noreferrer">Martin Fowler - GUI Architectures</a></li>
<li><a href="https://laravel.com/docs/11/views" target="_blank" rel="noopener noreferrer">Laravel Blade Templates Documentation</a></li>
</ul>