Refactorización de código legacy en PHP: cómo convertir el caos en orden
Cada desarrollador PHP, tarde o temprano, se enfrenta a código legacy: un proyecto antiguo, mal documentado y a menudo que no funciona. En lugar de reescribir todo desde cero (lo cual es arriesgado y costoso), una refactorización adecuada permite mejorar el código sin detener los procesos de negocio. En este artículo, analizaremos cómo refactorizar de forma segura proyectos PHP legacy, manteniendo su funcionalidad.
1. Evaluación y preparación: por dónde empezar la refactorización de código legacy
Antes de tocar el código, es necesario entender su estado actual. Si omites este paso, corres el riesgo de romperlo todo.
- Crea una copia de seguridad — un volcado completo de la base de datos y los archivos del proyecto.
- Realiza una auditoría — encuentra todos los puntos de entrada, dependencias y "cajas negras". Usa
greppara buscar funcionesinclude,require,evalymysql_*. - Configura el entorno — levanta una copia local del proyecto (Docker, Vagrant o XAMPP).
- Añade logging —
error_logy la monitorización ayudarán a rastrear errores después de los cambios.
Ejemplo de una auditoría simple a través de la consola:
# Búsqueda de funciones mysql obsoletasgrep -rn "mysql_query\\|mysql_connect\\|mysql_fetch" /path/to/legacy/project/Importante: si el proyecto no tiene pruebas, la refactorización se convierte en un juego de ruleta rusa. Lo primero es cubrir la lógica crítica con pruebas (aunque sean escenarios manuales documentados).
2. Estrategia de refactorización: pequeños pasos para grandes cambios
La mejor estrategia para el código legacy es la mejora gradual. No intentes reescribir todo el proyecto en un fin de semana. Usa el enfoque de la "regla del boy scout": deja el código más limpio de como lo encontraste.
2.1. Aísla los cambios
Cada cambio debe ser mínimo y atómico. Ejemplo: renombrar una variable en un archivo, luego extraer código duplicado en una función.
<?php// Antes de la refactorización (legacy)$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];$result = mysql_query($sql);
// Después: al menos escapamos$id = (int)$_GET['id'];$sql = "SELECT * FROM users WHERE id = $id";$result = mysqli_query($link, $sql);?>2.2. Usa herramientas de automatización
- PHPStan — análisis estático, encuentra errores sin ejecutar el código.
- Rector — refactorización automática (PSR-12, reemplazo de funciones obsoletas).
- PHP CodeSniffer — verificación del estilo del código.
- PHPUnit — pruebas unitarias.
Ejemplo de ejecución de Rector para reemplazar mysql_* por mysqli_*:
vendor/bin/rector process src/ --set mysql-to-mysqli3. Técnicas concretas de refactorización de código PHP
3.1. Reemplazo de "código espagueti" por POO
El código legacy a menudo se escribe como un archivo enorme con HTML y PHP mezclados. Separa la lógica en clases y funciones.
<?php// Mal: código mezclado$user = getUser($_GET['id']);echo "<h1>Hola, " . $user['name'] . "</h1>";if ($_POST['action'] === 'save') { saveUser($_POST);}
// Bien: separación de responsabilidadesclass UserController { public function show(int $id): void { $user = $this->userRepository->find($id); $this->render('profile', ['user' => $user]); }}?>3.2. Eliminación de código "muerto"
Funciones no utilizadas, comentarios, bloques comentados: todo esto crea ruido. Elimínalos sin piedad, pero verifica con git log que el código no se use en otro lugar.
// Búsqueda de funciones no utilizadas (requiere PHPStan)vendo