Aplicação 4: Exportador de Big Data com Generators e Streams

Exportar milhares de registros do banco de dados para um arquivo CSV pode facilmente derrubar um servidor por falta de memória.
Nesta aplicação, vamos construir um processador de exportação em lote (Batch Processor) que utiliza Generators do PHP.
Generators permitem percorrer grandes conjuntos de dados sem carregar tudo na RAM de uma só vez.
É a solução definitiva para lidar com Big Data dentro do ecossistema WordPress.
Vamos aprender a usar a técnica de “Cursor-based Pagination” para garantir que o MySQL não sofra com offsets pesados.

O Poder dos Generators (yield)

Um Generator é uma função que retorna um iterador.
Diferente de uma função comum que retorna um array, o Generator usa a palavra-chave yield.
Isso significa que ele produz um valor por vez e “pausa” a execução até que o próximo valor seja solicitado.
Didaticamente: é como ler uma página de um livro por vez, em vez de tentar memorizar o livro inteiro de uma só vez.
Isso reduz o consumo de memória de gigabytes para meros kilobytes, independente do tamanho do banco.

function get_all_posts_generator() {
    global $wpdb;
    $last_id = 0;
    
    while (true) {
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM wp_posts WHERE ID > %d ORDER BY ID ASC LIMIT 100",
            $last_id
        ));
        
        if (empty($rows)) break;
        
        foreach ($rows as $row) {
            $last_id = $row->ID;
            yield $row;
        }
    }
}

Observe que usamos ID > %d em vez de LIMIT offset, length.
Conforme o offset aumenta no MySQL, a consulta fica mais lenta porque o banco precisa contar todos os registros anteriores.
Usando o último ID processado, a busca é sempre feita via índice primário, o que é instantâneo.
Esta é a marca de um desenvolvedor sênior que entende de performance de banco de dados.
Agora, vamos gravar esses dados em um fluxo de arquivo (Stream).

header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.csv"');

$output = fopen('php://output', 'w');
fputcsv($output, ['ID', 'Título', 'Data']);

foreach (get_all_posts_generator() as $post) {
    fputcsv($output, [$post->ID, $post->post_title, $post->post_date]);
}
fclose($output);

O uso de php://output permite que o arquivo seja enviado diretamente para o navegador enquanto é gerado.
Não há criação de arquivo temporário no disco do servidor.
Isso economiza IOPS e evita problemas de permissão de pasta.
Esta ferramenta de exportação pode processar milhões de linhas em um servidor compartilhado sem estourar o memory_limit.
No MundoPHP, ensinamos você a dominar os recursos nativos da linguagem para criar soluções robustas.
Eficiência é a alma do desenvolvimento sênior.

Rolar para cima