Ferramentas & Produtividade

Como Usar PHP Moderno em Produção

8 min de leitura

Como Usar PHP Moderno em Produção

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. 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. 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

<h2>Estrutura de Projeto e Padrões Modernos</h2>

<p>PHP moderno em produção começa com uma arquitetura sólida. A maioria dos projetos sérios utiliza <strong>PSR-4 para autoloading</strong>, <strong>namespaces</strong> e o padrão <strong>MVC ou Clean Architecture</strong>. Isso não é opcional — é a base para manutenibilidade e escalabilidade. Usamos Composer como gerenciador de dependências, que padroniza a forma como importamos bibliotecas.</p>

<pre><code class="language-php">&lt;?php

// composer.json

{

&quot;name&quot;: &quot;meu-projeto/app&quot;,

&quot;require&quot;: {

&quot;php&quot;: &quot;&gt;=8.1&quot;,

&quot;symfony/http-foundation&quot;: &quot;^6.0&quot;,

&quot;doctrine/orm&quot;: &quot;^2.14&quot;

},

&quot;autoload&quot;: {

&quot;psr-4&quot;: {

&quot;App\\&quot;: &quot;src/&quot;

}

}

}

// 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-&gt;id;

}

}</code></pre>

<p>A estrutura de diretórios é essencial. Separe <strong>src/</strong> (código), <strong>tests/</strong> (testes), <strong>config/</strong> (configurações) e <strong>public/</strong> (entrada web). Nunca coloque lógica no public; use um único entry point.</p>

<h2>Segurança e Boas Práticas de Código</h2>

<p>Segurança em produção não é &quot;algo a mais&quot; — é fundamental. <strong>SQL injection, XSS, CSRF e validação inadequada</strong> continuam sendo os principais culpados de vazamentos. Use prepared statements sempre, valide inputs agressivamente e implemente rate limiting.</p>

<pre><code class="language-php">&lt;?php

// Errado: vulnerável a SQL injection

$user = $pdo-&gt;query(&quot;SELECT * FROM users WHERE email = &#039;{$_POST[&#039;email&#039;]}&#039;&quot;);

// Correto: prepared statement

$stmt = $pdo-&gt;prepare(&quot;SELECT * FROM users WHERE email = ?&quot;);

$stmt-&gt;execute([$_POST[&#039;email&#039;]]);

$user = $stmt-&gt;fetch();

// Validação robusta com filter_var

if (!filter_var($_POST[&#039;email&#039;], FILTER_VALIDATE_EMAIL)) {

throw new InvalidArgumentException(&#039;Email inválido&#039;);

}

// Proteção CSRF com tokens

session_start();

if (!isset($_SESSION[&#039;csrf_token&#039;])) {

$_SESSION[&#039;csrf_token&#039;] = bin2hex(random_bytes(32));

}

// Verificar no formulário

if ($_POST[&#039;csrf_token&#039;] !== $_SESSION[&#039;csrf_token&#039;]) {

throw new RuntimeException(&#039;Token CSRF inválido&#039;);

}

// Hashing seguro de senhas

$hash = password_hash($_POST[&#039;password&#039;], PASSWORD_ARGON2ID, [&#039;memory_cost&#039; =&gt; 65536]);

if (!password_verify($input_password, $hash)) {

throw new RuntimeException(&#039;Senha incorreta&#039;);

}

// Headers de segurança

header(&#039;Content-Security-Policy: default-src \&#039;self\&#039;&#039;);

header(&#039;X-Frame-Options: DENY&#039;);

header(&#039;X-Content-Type-Options: nosniff&#039;);

header(&#039;Strict-Transport-Security: max-age=31536000; includeSubDomains&#039;);</code></pre>

<p>Use <strong>type hints</strong> agressivamente (PHP 8.1+). Eles não são apenas boas práticas — são proteção contra bugs. Implemente <strong>early returns</strong> para reduzir complexidade ciclomática e sempre trate erros com exceções bem definidas.</p>

<h2>Testes, Logs e Monitoramento</h2>

<p>Código em produção sem testes é código quebrado que você ainda não descobriu. Implemente <strong>testes unitários, de integração e end-to-end</strong>. 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).</p>

<pre><code class="language-php">&lt;?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-&gt;repository = new UserRepository();

}

public function testFindByIdReturnsNullWhenNotFound(): void

{

$result = $this-&gt;repository-&gt;findById(999);

$this-&gt;assertNull($result);

}

public function testFindByIdReturnsUserInstance(): void

{

$user = $this-&gt;repository-&gt;findById(1);

$this-&gt;assertInstanceOf(User::class, $user);

$this-&gt;assertEquals(1, $user-&gt;getId());

}

}

// src/Logger/ApplicationLogger.php

namespace App\Logger;

use Monolog\Logger;

use Monolog\Handlers\StreamHandler;

class ApplicationLogger

{

private Logger $logger;

public function __construct()

{

$this-&gt;logger = new Logger(&#039;app&#039;);

$this-&gt;logger-&gt;pushHandler(

new StreamHandler(&#039;var/logs/app.log&#039;, Logger::DEBUG)

);

}

public function logUserLogin(int $userId): void

{

$this-&gt;logger-&gt;info(&#039;User login&#039;, [&#039;user_id&#039; =&gt; $userId]);

}

public function logException(\Throwable $e): void

{

$this-&gt;logger-&gt;error(&#039;Exception occurred&#039;, [

&#039;message&#039; =&gt; $e-&gt;getMessage(),

&#039;trace&#039; =&gt; $e-&gt;getTraceAsString()

]);

}

}</code></pre>

<p>Configure <strong>APM (Application Performance Monitoring)</strong> 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.</p>

<h2>Deploy, Variáveis de Ambiente e Performance</h2>

<p>Nunca commite credenciais ou configurações no Git. Use <strong>dotenv</strong> para gerenciar variáveis de ambiente. Separe claramente configuração (que muda entre ambientes) de código.</p>

<pre><code class="language-php">&lt;?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__ . &#039;/..&#039;);

$dotenv-&gt;load();

$url = $_ENV[&#039;DATABASE_URL&#039;];

return new \PDO($url);

}

}</code></pre>

<p>Para performance, implemente <strong>caching em múltiplas camadas</strong>: Redis para sessão e dados quentes, APCu para dados estáticos, e HTTP caching via headers. Use <strong>lazy loading</strong>, evite N+1 queries com eager loading em ORMs, e perfil seu código com Xdebug ou Blackfire.</p>

<pre><code class="language-php">&lt;?php

// Cache com Redis

$redis = new Redis();

$redis-&gt;connect(&#039;127.0.0.1&#039;, 6379);

$cacheKey = &#039;user:&#039; . $userId;

$user = $redis-&gt;get($cacheKey);

if ($user === false) {

$user = $repository-&gt;findById($userId); // Query ao BD

$redis-&gt;setex($cacheKey, 3600, serialize($user)); // Cache por 1h

}

// Eager loading para evitar N+1

$users = $repository-&gt;findAllWithPosts(); // JOINs no SQL</code></pre>

<h2>Conclusão</h2>

<p>Dominar PHP moderno em produção exige três pilares: <strong>(1) Arquitetura sólida</strong> com padrões, namespaces e estrutura clara; <strong>(2) Segurança rigorosa</strong> com validação, prepared statements e headers apropriados; <strong>(3) Observabilidade</strong> via testes, logs estruturados e monitoramento real-time. Não pule essas etapas por &quot;ganho de tempo&quot; — código inseguro ou difícil de debugar custará muito mais depois.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://phptherightway.com/" target="_blank" rel="noopener noreferrer">PHP: The Right Way</a></li>

<li><a href="https://www.php.net/manual/pt_BR/" target="_blank" rel="noopener noreferrer">Documentação Oficial PHP 8.1+</a></li>

<li><a href="https://symfony.com/doc/current/best_practices.html" target="_blank" rel="noopener noreferrer">Symfony Best Practices</a></li>

<li><a href="https://owasp.org/www-project-web-security-testing-guide/" target="_blank" rel="noopener noreferrer">OWASP Security Testing Guide</a></li>

<li><a href="https://www.php-fig.org/" target="_blank" rel="noopener noreferrer">PHP Standards Recommendations (PSR)</a></li>

</ul>

Comentários

Mais em Ferramentas & Produtividade

Logs que realmente respondem perguntas: do clique no React até o banco de dados
Logs que realmente respondem perguntas: do clique no React até o banco de dados

Bug às 23h, mil linhas de log sem contexto. Veja como estruturar logs rastreá...

Dominando Cache e Performance em Projetos Reais
Dominando Cache e Performance em Projetos Reais

Cache: Fundamentos e Estratégias Práticas Cache é um mecanismo de armazenamen...

Dominando Segurança em APIs em Projetos Reais
Dominando Segurança em APIs em Projetos Reais

Autenticação e Autorização: O Primeiro Pilar A segurança de uma API começa co...