PHP y Big Data: no es un oxímoron, sino una realidad
Cuando escuchas "procesamiento de grandes datos", lo primero que viene a la mente es Spark, Hadoop o Python con Pandas. PHP en esta lista generalmente se percibe como "un lenguaje para landing pages y foros". Pero seamos realistas: si tu proyecto ya vive en PHP, reescribirlo completamente en Go para una sola tarea de procesar un CSV de gigabytes es como matar moscas a cañonazos.
PHP maneja Big Data perfectamente si se aborda el problema con inteligencia. En este artículo, analizaremos técnicas reales: cómo no matar el servidor trabajando con archivos de 10+ GB, cómo procesar millones de filas de una base de datos sin out of memory, y cómo convertir PHP en un verdadero pipeline de datos. Sin rodeos, solo código y soluciones arquitectónicas.
Por qué PHP "no ama" los grandes datos (y cómo solucionarlo)
El principal problema de PHP en el contexto de Big Data es su modelo de ejecución. El script se ejecuta secuencialmente, cargando todo en memoria. Intente hacer file_get_contents() en un archivo de 5 GB: el servidor simplemente se caerá.
Pero hay una buena noticia: PHP tiene mecanismos integrados para el procesamiento por flujo. Solo necesita olvidarse de métodos "bárbaros" como file() o file_get_contents() y pasar a generadores, flujos y consultas chunk.
Generadores: tu herramienta principal
Los generadores (palabra clave yield) permiten devolver datos elemento por elemento, sin cargar todo el conjunto en memoria. Esto es ideal para leer archivos grandes o consultas de bases de datos.
Ejemplo: leemos un archivo CSV de 5 GB línea por línea, sin matar la memoria:
<?phpfunction readLargeCSV(string $filePath): Generator{ $handle = fopen($filePath, 'r'); if ($handle === false) { throw new RuntimeException("No se pudo abrir el archivo: $filePath"); }
// Omitimos BOM si existe $bom = fread($handle, 3); if ($bom !== "\\xEF\\xBB\\xBF") { rewind($handle); // Si no hay BOM, volvemos al inicio }
while (($row = fgetcsv($handle, 0, ',')) !== false) { yield $row; }
fclose($handle);}
// Usoforeach (readLargeCSV('/data/orders_2024.csv') as $index => $row) { // Procesamos cada línea una por una if ($index === 0) { continue; // omitimos el encabezado } processOrder($row);}?>¿Por qué funciona esto? El generador no carga todo el archivo en un array. Lee una línea, la entrega, lee la siguiente. El consumo de memoria se mantiene en unos pocos kilobytes, independientemente del tamaño del archivo.
Trabajo con grandes bases de datos: Consultas Chunk
Si necesita procesar 5 millones de registros de MySQL, no intente hacer SELECT * FROM table — eso matará tanto a la BD como a PHP. En su lugar, use cursores o consultas chunk.
Aquí está el enfoque correcto usando PDO e iteración chunk:
<?phpfunction processLargeTable(PDO $pdo, int $chunkSize = 1000, callable $callback): void{ $offset = 0; $lastId = 0;
// Usamos ORDER BY id para estabilidad $stmt = $pdo->prepare("SELECT * FROM orders WHERE id > :lastId ORDER BY id LIMIT :limit");
do { $stmt->execute(['lastId' => $lastId, 'limit' => $chunkSize]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($rows)) { break; }
foreach ($rows as $row) { $callback($row); $lastId = $row['id']; // Recordamos el último ID procesado }
// Liberamos memoria unset($rows); $stmt->closeCursor();
} while (true);}
// Uso$pdo = new PDO('mysql:host=localhost;dbname=big_data', 'user', 'pass');$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
p