¿Tu sitio PHP va lento? Es hora de mirar bajo el capó
\n\n¿Alguna vez has esperado a que cargue una página más tiempo del que tardas en tomarte tu café matutino? Un dolor familiar. PHP es un lenguaje potente, pero sin la configuración adecuada puede convertirse en una tortuga. En este artículo no daremos aburridas conferencias. Tomaremos código real, lo perfilaremos, encontraremos los cuellos de botella y lo aceleraremos tanto que el servidor te lo agradecerá.
\n\nHablaremos sobre el rendimiento de PHP, desde mediciones simples hasta un perfilado profundo. Aprenderás cómo usar Xdebug y Blackfire para encontrar las secciones problemáticas, y qué métodos de optimización realmente funcionan. ¡Allá vamos!
\n\nPaso 1. Midamos todo: de microsegundos a megabytes
\n\nAntes de optimizar algo, debemos entender dónde está el cuello de botella. La intuición a menudo falla. Usemos herramientas.
\n\nLa forma más simple: microtime(true)
\n\nPara una comprobación rápida de un fragmento de código, sirve el clásico microtime(). No es elegante, pero funciona.
<?php\n$start = microtime(true);\n\n// Tu código lento\n$data = [];\nfor ($i = 0; $i < 100000; $i++) {\n $data[] = md5($i . 'salt');\n}\n\n$end = microtime(true);\necho 'Tiempo de ejecución: ' . round(($end - $start) * 1000, 2) . ' ms';\n?>\n\nEste método es bueno para una estimación aproximada. Pero cuando el proyecto crece, se necesitan herramientas serias.
\n\nXdebug — tu detective personal
\n\nXdebug es el estándar de facto para el perfilado de PHP. Genera archivos cachegrind que se pueden abrir en KCachegrind (Linux) o QCachegrind (Mac/Windows).
\n\nInstalación mediante pecl:
\npecl install xdebug\n\nHabilitamos el perfilado en php.ini:
\nxdebug.mode = profile\nxdebug.output_dir = /tmp/profiling\n\nDespués de ejecutar el script, aparecerá un archivo en la carpeta. Ábrelo en QCachegrind: verás qué función consumió más tiempo. A menudo la sorpresa: no es la base de datos, sino un simple procesamiento de cadenas en un bucle.
\n\nBlackfire — para los que aman los paneles bonitos
\n\nBlackfire de SensioLabs (los creadores de Symfony) es un perfilador en la nube. Muestra no solo el tiempo, sino también el número de llamadas, la memoria y la E/S. Se integra con PHPUnit, Symfony y Laravel.
\n\nEjemplo de uso desde la línea de comandos:
\nblackfire run php myscript.php\n\nObtendrás un enlace a un informe web con visualización. Es útil para encontrar cuellos de botella de rendimiento en PHP.
\n\nPaso 2. Problemas típicos y sus soluciones
\n\nAhora que sabemos perfilar, analicemos los problemas comunes.
\n\nProblema 1: Consultas N+1 en un bucle
\n\nUn clásico. Obtienes una lista de usuarios y luego, en un bucle, haces una consulta a la BD para cada uno.
\n\nCódigo lento:
\n<?php\n$users = $db->query('SELECT id FROM users LIMIT 100');\nforeach ($users as $user) {\n $orders = $db->query("SELECT * FROM orders WHERE user_id = {$user['id']}");\n // ...\n}\n?>\n\nOptimización:
\n<?php\n$users = $db->query('SELECT id FROM users LIMIT 100');\n$ids = array_column($users, 'id');\n$orders = $db->query('SELECT * FROM orders WHERE user_id IN (' . implode(',', $ids) . ')');\n// Agrupamos por user_id\n$grouped = [];\nforeach ($orders as $order) {\n $grouped[$order['user_id']][] = $order;\n}\n?>\n\nResultado: 100 consultas se convirtieron en 2. El rendimiento de la aplicación PHP aumenta varias veces.
\n\nProblema 2: Bucles ineficientes y trabajo con cadenas
\n\nLa concatenación de cadenas en un bucle es mala. Usa arrays y implode().
<?php\n// Malo\n$result = '';\nfor ($i = 0; $i < 10000; $i++) {\n $result .= 'item' . $i . ',';\n}\n\n// Bueno\n$parts = [];\nfor ($i =