Makrosites

Suas ideias em realidade digital!

Performance em PHP: como deixar API e site mais rápidos sem framework

Performance em PHP: como deixar API e site mais rápidos sem framework >

Melhorar a performance em PHP é essencial para qualquer site, sistema ou API que precisa responder rápido, consumir menos recursos e oferecer uma boa experiência para o usuário. Quando uma aplicação PHP começa a ficar lenta, o problema pode estar no banco de dados, em consultas pesadas, ausência de cache, arquivos grandes, respostas JSON extensas, falta de paginação ou configuração incorreta do servidor.

A boa notícia é que você não precisa usar um framework para deixar sua aplicação mais rápida. Com PHP puro, boas práticas de banco de dados, OPcache, cache simples, compressão e organização do código, já é possível melhorar bastante o tempo de resposta do sistema.

Neste artigo, você vai aprender como melhorar a performance de uma API ou site em PHP sem framework, com exemplos práticos para aplicar em projetos reais.

Resumo prático: antes de tentar otimizar tudo, descubra onde está a lentidão. Meça tempo de resposta, analise consultas SQL, reduza dados desnecessários e use cache quando fizer sentido.

Por que uma aplicação PHP fica lenta?

Uma aplicação PHP pode ficar lenta por vários motivos. Nem sempre o problema está no PHP em si. Muitas vezes, a lentidão vem de consultas SQL mal otimizadas, retorno excessivo de dados, falta de índices no banco, arquivos pesados ou lógica mal estruturada.

Algumas causas comuns de lentidão são:

Primeiro passo: medir o tempo de execução

Antes de otimizar, você precisa medir. Sem medição, qualquer mudança vira tentativa no escuro.

Uma forma simples de medir o tempo de execução de um script PHP é usando microtime.

<?php

$inicio = microtime(true);

// Código da aplicação aqui

$fim = microtime(true);
$tempo = $fim - $inicio;

echo 'Tempo de execução: ' . round($tempo, 4) . ' segundos';

Em APIs, você pode registrar esse tempo no log em vez de exibir na tela.

<?php

$inicio = microtime(true);

// Processamento da API

$tempo = microtime(true) - $inicio;

error_log('Tempo de resposta da API: ' . round($tempo, 4) . ' segundos');

Essa medição ajuda a identificar endpoints lentos, relatórios pesados e consultas demoradas.

Evite retornar todos os registros de uma vez

Um dos maiores problemas de performance em APIs PHP é retornar listas enormes sem paginação. Mesmo que funcione no começo, quando a tabela cresce, o sistema começa a ficar lento.

Evite consultas assim:

SELECT * FROM pedidos ORDER BY id DESC

Em uma tabela com milhares de registros, isso pode consumir memória, tempo de banco e tráfego desnecessário.

Prefira usar paginação:

SELECT id, cliente, status, created_at
FROM pedidos
ORDER BY id DESC
LIMIT 20 OFFSET 0

Assim, a API retorna apenas os dados necessários para a página atual.

Paginação em API PHP

Um exemplo simples de paginação em PHP:

<?php

$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
$limit = isset($_GET['limit']) ? (int) $_GET['limit'] : 20;

if ($page < 1) {
    $page = 1;
}

if ($limit < 1) {
    $limit = 20;
}

if ($limit > 100) {
    $limit = 100;
}

$offset = ($page - 1) * $limit;

$sql = "
    SELECT id, cliente, status, created_at
    FROM pedidos
    ORDER BY id DESC
    LIMIT :limit OFFSET :offset
";

$stmt = $pdo->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();

$pedidos = $stmt->fetchAll();

Além de melhorar performance, limitar o máximo de registros por página evita abuso da API.

Evite SELECT * em consultas SQL

O uso de SELECT * pode trazer colunas desnecessárias, aumentando o volume de dados processado pelo banco, transferido para o PHP e enviado para o frontend.

Evite:

SELECT * FROM usuarios

Prefira:

SELECT id, nome, email, status FROM usuarios

Retorne apenas os campos que realmente serão usados na tela ou na API.

Crie índices nos campos mais usados

Índices ajudam o banco de dados a encontrar registros mais rapidamente. Se sua aplicação filtra muito por email, status, created_at ou usuario_id, esses campos podem precisar de índice.

CREATE INDEX idx_usuarios_email ON usuarios(email);
CREATE INDEX idx_usuarios_status ON usuarios(status);
CREATE INDEX idx_pedidos_created_at ON pedidos(created_at);
CREATE INDEX idx_pedidos_usuario_id ON pedidos(usuario_id);

Índices melhoram buscas e filtros, mas devem ser usados com cuidado. Índices demais podem impactar gravações, então priorize campos realmente usados em consultas frequentes.

Use EXPLAIN para analisar consultas MySQL

O comando EXPLAIN ajuda a entender como o MySQL executa uma consulta.

EXPLAIN SELECT id, nome, email
FROM usuarios
WHERE email = 'teste@exemplo.com';

Com ele, você consegue identificar se a consulta está usando índice ou fazendo varredura completa na tabela.

Se uma consulta importante está lenta, usar EXPLAIN é um bom caminho para descobrir o gargalo.

Reduza o tamanho da resposta JSON

Em APIs, o tamanho da resposta influencia diretamente a performance. Quanto mais dados você envia, mais tempo a API leva para montar, transferir e o frontend interpretar.

Evite respostas com campos desnecessários:

{
  "id": 1,
  "nome": "João",
  "email": "joao@exemplo.com",
  "senha": "$2y$10$...",
  "token_interno": "abc",
  "observacoes_internas": "..."
}

Prefira retornar apenas o necessário:

{
  "id": 1,
  "nome": "João",
  "email": "joao@exemplo.com"
}
Atenção: nunca retorne senha, hash de senha, tokens internos ou dados sensíveis desnecessários em respostas JSON.

Use cache para dados que não mudam sempre

Cache é uma técnica para guardar temporariamente o resultado de uma operação pesada. Assim, em vez de consultar o banco toda vez, a aplicação pode reaproveitar um resultado salvo por alguns minutos.

Exemplos de dados que podem usar cache:

Cache simples em arquivo com PHP

Um cache simples em arquivo pode resolver muitos casos em projetos pequenos e médios.

<?php

function cacheGet(string $key, int $ttlSeconds): ?array
{
    $cacheDir = __DIR__ . '/cache';

    if (!is_dir($cacheDir)) {
        mkdir($cacheDir, 0755, true);
    }

    $file = $cacheDir . '/' . md5($key) . '.json';

    if (!file_exists($file)) {
        return null;
    }

    if ((time() - filemtime($file)) > $ttlSeconds) {
        unlink($file);
        return null;
    }

    $content = file_get_contents($file);

    return json_decode($content, true);
}

function cacheSet(string $key, array $data): void
{
    $cacheDir = __DIR__ . '/cache';

    if (!is_dir($cacheDir)) {
        mkdir($cacheDir, 0755, true);
    }

    $file = $cacheDir . '/' . md5($key) . '.json';

    file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE));
}

Exemplo de uso:

<?php

$cacheKey = 'categorias_ativas';
$categorias = cacheGet($cacheKey, 300); // 5 minutos

if ($categorias === null) {
    $stmt = $pdo->query("SELECT id, nome FROM categorias WHERE status = 'ativo'");
    $categorias = $stmt->fetchAll();

    cacheSet($cacheKey, $categorias);
}

echo json_encode([
    'success' => true,
    'data' => $categorias
]);

Esse tipo de cache reduz consultas repetidas ao banco.

Ative OPcache no PHP

O OPcache melhora a performance armazenando scripts PHP pré-compilados em memória. Sem ele, o PHP precisa carregar e compilar os arquivos a cada requisição.

Em servidores de produção, o OPcache deve estar ativado sempre que possível.

Exemplo de configuração básica no php.ini:

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2

Em produção, algumas configurações podem variar conforme o servidor e o fluxo de deploy. O importante é verificar se o OPcache está ativo.

Como verificar se OPcache está ativo

Você pode criar temporariamente um arquivo com phpinfo.

<?php
phpinfo();

Depois procure por OPcache na página.

Atenção: remova o arquivo com phpinfo depois do teste. Ele expõe informações sensíveis do servidor.

Evite loops desnecessários

Loops mal planejados podem afetar muito a performance, principalmente quando fazem consultas ao banco dentro de cada repetição.

Evite:

<?php

foreach ($usuarios as $usuario) {
    $stmt = $pdo->prepare("SELECT COUNT(*) FROM pedidos WHERE usuario_id = :id");
    $stmt->execute([
        ':id' => $usuario['id']
    ]);

    $totalPedidos = $stmt->fetchColumn();
}

Esse padrão é conhecido como problema N+1: para cada usuário, uma nova consulta é feita.

Prefira buscar tudo em uma consulta com JOIN ou agrupamento:

SELECT u.id, u.nome, COUNT(p.id) AS total_pedidos
FROM usuarios u
LEFT JOIN pedidos p ON p.usuario_id = u.id
GROUP BY u.id, u.nome

Use JOIN com cuidado

JOIN pode melhorar performance ao evitar várias consultas, mas também pode ficar pesado se usado sem índices ou sem necessidade.

Sempre que usar JOIN, confira:

Comprima respostas com Gzip ou Brotli

A compressão reduz o tamanho transferido entre servidor e navegador. Isso ajuda especialmente em respostas HTML, CSS, JavaScript e JSON.

Em muitos servidores, a compressão é configurada no Apache, Nginx ou painel da hospedagem.

No Apache, pode-se usar mod_deflate. No Nginx, a compressão geralmente é ativada com diretivas de gzip.

Para APIs que retornam JSON grande, compressão pode reduzir bastante o tamanho da resposta.

Otimize imagens do site

Sites PHP muitas vezes ficam lentos não por causa do PHP, mas por causa de imagens pesadas. Use imagens redimensionadas, formatos modernos como WebP e carregamento sob demanda quando possível.

Boas práticas:

Use headers de cache para arquivos estáticos

Arquivos como CSS, JavaScript, imagens e fontes podem ser armazenados no cache do navegador. Isso reduz novas requisições e melhora o carregamento em visitas futuras.

Exemplo para Apache com .htaccess:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/webp "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType text/css "access plus 7 days"
    ExpiresByType application/javascript "access plus 7 days"
</IfModule>

Isso ajuda muito em sites com muitos recursos estáticos.

Evite carregar arquivos PHP desnecessários

Se sua aplicação usa muitos require ou include, verifique se está carregando apenas o necessário.

Arquivos grandes e não utilizados aumentam o tempo de inicialização. Organize helpers, controllers e serviços para carregar somente o que a rota precisa.

Use Composer autoload quando o projeto crescer

Mesmo em PHP puro, você pode usar o autoload do Composer para organizar classes. Isso evita uma sequência grande de require_once.

{
  "autoload": {
    "psr-4": {
      "App\\": "app/"
    }
  }
}

Depois:

composer dump-autoload

E no PHP:

<?php

require __DIR__ . '/vendor/autoload.php';

Isso deixa o projeto mais organizado e facilita manutenção.

Evite processamento pesado em requisições comuns

Algumas tarefas não deveriam acontecer diretamente durante uma requisição normal do usuário.

Exemplos:

Sempre que possível, divida o processamento em partes, use filas, tarefas agendadas ou rotinas separadas.

Use paginação em relatórios grandes

Relatórios são uma das maiores causas de lentidão em sistemas PHP. Em vez de gerar tudo de uma vez, aplique filtros e paginação.

SELECT id, cliente, valor, created_at
FROM vendas
WHERE created_at BETWEEN :inicio AND :fim
ORDER BY created_at DESC
LIMIT :limit OFFSET :offset

Para exportações muito grandes, considere processar em lotes.

Registre endpoints lentos em log

Uma boa prática é registrar no log quando uma requisição ultrapassa determinado tempo.

<?php

$inicio = microtime(true);

// código da API

$duracao = microtime(true) - $inicio;

if ($duracao > 1.5) {
    error_log('Endpoint lento: ' . ($_SERVER['REQUEST_URI'] ?? '') . ' - ' . round($duracao, 4) . 's');
}

Assim, você consegue descobrir quais rotas precisam de otimização.

Configure limites de memória com cuidado

Aumentar memory_limit pode resolver temporariamente alguns erros, mas nem sempre é a solução correta. Se uma requisição consome memória demais, pode haver consulta sem paginação, loop pesado ou processamento exagerado.

Exemplo de configuração:

memory_limit = 256M
max_execution_time = 60

Use esses ajustes com cuidado e investigue a causa da lentidão.

Performance em API PHP: exemplo completo com paginação e log

<?php

header('Content-Type: application/json; charset=utf-8');

$inicio = microtime(true);

function jsonResponse(int $statusCode, array $data): void
{
    global $inicio;

    $duracao = microtime(true) - $inicio;

    if ($duracao > 1.5) {
        error_log('Resposta lenta: ' . ($_SERVER['REQUEST_URI'] ?? '') . ' - ' . round($duracao, 4) . 's');
    }

    http_response_code($statusCode);
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

try {
    $pdo = new PDO(
        'mysql:host=localhost;dbname=sua_base;charset=utf8mb4',
        'usuario',
        'senha',
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false
        ]
    );

    $page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
    $limit = isset($_GET['limit']) ? (int) $_GET['limit'] : 20;

    if ($page < 1) {
        $page = 1;
    }

    if ($limit < 1) {
        $limit = 20;
    }

    if ($limit > 100) {
        $limit = 100;
    }

    $offset = ($page - 1) * $limit;

    $sql = "
        SELECT id, nome, email, status
        FROM usuarios
        ORDER BY id DESC
        LIMIT :limit OFFSET :offset
    ";

    $stmt = $pdo->prepare($sql);
    $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
    $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
    $stmt->execute();

    $usuarios = $stmt->fetchAll();

    jsonResponse(200, [
        'success' => true,
        'data' => $usuarios,
        'pagination' => [
            'page' => $page,
            'limit' => $limit
        ]
    ]);

} catch (PDOException $e) {
    error_log('Erro PDO: ' . $e->getMessage());

    jsonResponse(500, [
        'success' => false,
        'message' => 'Erro interno ao consultar os dados.'
    ]);

} catch (Throwable $e) {
    error_log('Erro inesperado: ' . $e->getMessage());

    jsonResponse(500, [
        'success' => false,
        'message' => 'Erro interno no servidor.'
    ]);
}

Checklist para melhorar performance em PHP

Erros comuns ao otimizar PHP

1. Otimizar sem medir

Antes de mudar o código, meça o tempo de resposta e identifique o gargalo real.

2. Achar que o problema sempre é o PHP

Muitas vezes, a lentidão está no banco, em imagens, no servidor ou em consultas sem índice.

3. Retornar dados demais na API

Quanto maior a resposta, maior o custo para servidor, rede e frontend.

4. Ignorar OPcache

OPcache é uma das otimizações mais importantes em servidores PHP de produção.

5. Usar cache em dados que precisam ser sempre atualizados

Cache é útil, mas precisa ser aplicado com cuidado para não mostrar informações desatualizadas.

Conclusão

Melhorar a performance em PHP não depende obrigatoriamente de framework. Com PHP puro, você já pode aplicar boas práticas importantes como paginação, consultas otimizadas, índices no banco, cache simples, OPcache, compressão e logs de endpoints lentos.

O mais importante é medir antes de otimizar. Descubra se o gargalo está no banco, no PHP, no tamanho da resposta, em imagens pesadas ou em processamento excessivo. Depois disso, aplique a correção certa.

Com uma estrutura bem organizada, sua API ou site PHP pode ficar mais rápido, mais econômico e mais preparado para crescer.

Perguntas frequentes sobre performance em PHP

Como melhorar a performance de um site PHP?

Meça o tempo de resposta, otimize consultas SQL, use paginação, ative OPcache, reduza arquivos pesados, use cache e comprima recursos estáticos.

OPcache melhora mesmo o desempenho do PHP?

Sim. O OPcache evita que o PHP precise recompilar scripts a cada requisição, melhorando a performance em ambientes de produção.

Por que minha API PHP está lenta?

As causas mais comuns são consultas SQL pesadas, ausência de paginação, retorno excessivo de dados, falta de índices, loops desnecessários ou servidor com poucos recursos.

Cache em arquivo funciona em PHP?

Sim. Para projetos pequenos e médios, cache em arquivo pode reduzir consultas repetidas ao banco e melhorar o tempo de resposta.

SELECT * prejudica performance?

Pode prejudicar, principalmente em tabelas grandes ou com muitas colunas. O ideal é retornar apenas os campos necessários.

Paginação melhora performance?

Sim. Paginação reduz a quantidade de dados processados, transferidos e renderizados pelo frontend.

Perguntas frequentes sobre performance em PHP

Como melhorar a performance de um site PHP?

Meça o tempo de resposta, otimize consultas SQL, use paginação, ative OPcache, reduza arquivos pesados, use cache e comprima recursos estáticos.

OPcache melhora mesmo o desempenho do PHP?

Sim. O OPcache evita que o PHP precise recompilar scripts a cada requisição, melhorando a performance em ambientes de produção.

Por que minha API PHP está lenta?

As causas mais comuns são consultas SQL pesadas, ausência de paginação, retorno excessivo de dados, falta de índices, loops desnecessários ou servidor com poucos recursos.

Cache em arquivo funciona em PHP?

Sim. Para projetos pequenos e médios, cache em arquivo pode reduzir consultas repetidas ao banco e melhorar o tempo de resposta.

SELECT * prejudica performance?

Pode prejudicar, principalmente em tabelas grandes ou com muitas colunas. O ideal é retornar apenas os campos necessários.

Paginação melhora performance?

Sim. Paginação reduz a quantidade de dados processados, transferidos e renderizados pelo frontend.