Estrutura de Projeto e Padrões Modernos
PHP moderno em produção começa com uma arquitetura sólida. A maioria dos projetos sérios utiliza PSR-4 para autoloading, namespaces e o padrão MVC ou Clean Architecture. Isso não é opcional — é a base para manutenibilidade e escalabilidade. Usamos Composer como gerenciador de dependências, que padroniza a forma como importamos bibliotecas.
<?php
// composer.json
{
"name": "meu-projeto/app",
"require": {
"php": ">=8.1",
"symfony/http-foundation": "^6.0",
"doctrine/orm": "^2.14"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
// src/User/UserRepository.php
namespace App\User;
class UserRepository
{
public function findById(int $id): ?User
{
// Implementação
return null;
}
}
// src/User/User.php
namespace App\User;
class User
{
public function __construct(
private int $id,
private string $email,
private string $password
) {}
public function getId(): int
{
return $this->id;
}
}
A estrutura de diretórios é essencial. Separe src/ (código), tests/ (testes), config/ (configurações) e public/ (entrada web). Nunca coloque lógica no public; use um único entry point.
Segurança e Boas Práticas de Código
Segurança em produção não é "algo a mais" — é fundamental. SQL injection, XSS, CSRF e validação inadequada continuam sendo os principais culpados de vazamentos. Use prepared statements sempre, valide inputs agressivamente e implemente rate limiting.
<?php
// Errado: vulnerável a SQL injection
$user = $pdo->query("SELECT * FROM users WHERE email = '{$_POST['email']}'");
// Correto: prepared statement
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$_POST['email']]);
$user = $stmt->fetch();
// Validação robusta com filter_var
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Email inválido');
}
// Proteção CSRF com tokens
session_start();
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// Verificar no formulário
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
throw new RuntimeException('Token CSRF inválido');
}
// Hashing seguro de senhas
$hash = password_hash($_POST['password'], PASSWORD_ARGON2ID, ['memory_cost' => 65536]);
if (!password_verify($input_password, $hash)) {
throw new RuntimeException('Senha incorreta');
}
// Headers de segurança
header('Content-Security-Policy: default-src \'self\'');
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
Use type hints agressivamente (PHP 8.1+). Eles não são apenas boas práticas — são proteção contra bugs. Implemente early returns para reduzir complexidade ciclomática e sempre trate erros com exceções bem definidas.
Testes, Logs e Monitoramento
Código em produção sem testes é código quebrado que você ainda não descobriu. Implemente testes unitários, de integração e end-to-end. Use PHPUnit para testes estruturados e mantenha cobertura acima de 80%. Logs estruturados com Monolog permitem rastrear problemas em produção; use níveis apropriados (DEBUG, INFO, WARNING, ERROR, CRITICAL).
<?php
// tests/User/UserRepositoryTest.php
namespace Tests\User;
use App\User\UserRepository;
use PHPUnit\Framework\TestCase;
class UserRepositoryTest extends TestCase
{
private UserRepository $repository;
protected function setUp(): void
{
$this->repository = new UserRepository();
}
public function testFindByIdReturnsNullWhenNotFound(): void
{
$result = $this->repository->findById(999);
$this->assertNull($result);
}
public function testFindByIdReturnsUserInstance(): void
{
$user = $this->repository->findById(1);
$this->assertInstanceOf(User::class, $user);
$this->assertEquals(1, $user->getId());
}
}
// src/Logger/ApplicationLogger.php
namespace App\Logger;
use Monolog\Logger;
use Monolog\Handlers\StreamHandler;
class ApplicationLogger
{
private Logger $logger;
public function __construct()
{
$this->logger = new Logger('app');
$this->logger->pushHandler(
new StreamHandler('var/logs/app.log', Logger::DEBUG)
);
}
public function logUserLogin(int $userId): void
{
$this->logger->info('User login', ['user_id' => $userId]);
}
public function logException(\Throwable $e): void
{
$this->logger->error('Exception occurred', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
}
}
Configure APM (Application Performance Monitoring) como Sentry ou NewRelic. Logs locais são insuficientes em produção — você precisa visibilidade em tempo real sobre performance, erros e comportamento do usuário.
Deploy, Variáveis de Ambiente e Performance
Nunca commite credenciais ou configurações no Git. Use dotenv para gerenciar variáveis de ambiente. Separe claramente configuração (que muda entre ambientes) de código.
<?php
// .env.example (commitar no repositório)
DATABASE_URL=mysql://user:pass@localhost/dbname
REDIS_URL=redis://localhost:6379
LOG_LEVEL=DEBUG
APP_ENV=development
// .env (NÃO commitar — apenas local/produção)
DATABASE_URL=mysql://prod_user:prod_pass@prod-db:3306/prod_db
REDIS_URL=redis://prod-cache:6379
LOG_LEVEL=WARNING
APP_ENV=production
// config/Database.php
namespace App\Config;
use Dotenv\Dotenv;
class Database
{
public static function connect(): \PDO
{
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
$url = $_ENV['DATABASE_URL'];
return new \PDO($url);
}
}
Para performance, implemente caching em múltiplas camadas: Redis para sessão e dados quentes, APCu para dados estáticos, e HTTP caching via headers. Use lazy loading, evite N+1 queries com eager loading em ORMs, e perfil seu código com Xdebug ou Blackfire.
<?php
// Cache com Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cacheKey = 'user:' . $userId;
$user = $redis->get($cacheKey);
if ($user === false) {
$user = $repository->findById($userId); // Query ao BD
$redis->setex($cacheKey, 3600, serialize($user)); // Cache por 1h
}
// Eager loading para evitar N+1
$users = $repository->findAllWithPosts(); // JOINs no SQL
Conclusão
Dominar PHP moderno em produção exige três pilares: (1) Arquitetura sólida com padrões, namespaces e estrutura clara; (2) Segurança rigorosa com validação, prepared statements e headers apropriados; (3) Observabilidade via testes, logs estruturados e monitoramento real-time. Não pule essas etapas por "ganho de tempo" — código inseguro ou difícil de debugar custará muito mais depois.