Introducción: por qué la refactorización de código legacy no es un lujo, sino una necesidad
Cada desarrollador PHP tarde o temprano se enfrenta a código legacy. Puede ser un proyecto escrito hace 10 años en PHP 5.3, o una aplicación que «simplemente funciona», pero causa dolor con cada cambio. La refactorización de dicho código no es solo «peinar» el estilo, sino un proceso críticamente importante que mejora la mantenibilidad, el rendimiento y la seguridad de la aplicación.
En este artículo analizaremos enfoques prácticos para la refactorización de código PHP legacy, utilizando las capacidades modernas del lenguaje (PHP 7.4–8.3) y patrones probados. Aprenderá cómo realizar cambios de forma segura sin romper el sistema en funcionamiento.
1. Evaluación y documentación del estado actual
El primer paso y el más importante es entender con qué está tratando. No intente refactorizar a ciegas.
1.1. Cree un mapa de dependencias
Utilice herramientas como PhpMetrics o Deptrac para visualizar las conexiones entre clases. Esto ayudará a identificar «objetos divinos» (god objects) y dependencias cíclicas.
// Ejemplo de una clase "divina" típica en código legacyclass UserManager { public function save($data) { // 200 líneas de código: validación, envío de email, registro, trabajo con BD } public function sendNewsletter() { // Otras 150 líneas } public function generateReport() { // Y otras 100 líneas }}1.2. Escriba pruebas de caracterización
Antes de cambiar el código, asegúrese de que el comportamiento actual esté documentado con pruebas. Utilice el enfoque «Golden Master» (snapshot testing):
// Prueba que fija el comportamiento actualpublic function testLegacyCalculation(): void{ $calculator = new OldCalculator(); $result = $calculator->compute(10, 20); // Si no hay especificación, simplemente guardamos el resultado $this->assertSame(30, $result);}Consejo: Si el proyecto no tiene pruebas en absoluto, comience con pruebas de integración para las operaciones comerciales críticas. Utilice PHPUnit con vfsStream para aislar el sistema de archivos.
2. Mejora por etapas: de funciones globales a POO
La mayor parte del código PHP legacy consiste en funciones globales y estilo procedural. La migración gradual a POO es una etapa clave de la refactorización.
2.1. Encapsulación de funciones globales
Reemplace las funciones globales por métodos estáticos de clase, luego por servicios completos.
// Antes: función globalfunction send_email($to, $subject, $message) { mail($to, $subject, $message);}
// Después: clase de servicioclass MailService { public function __construct( private MailerInterface $mailer ) {} public function send(string $to, string $subject, string $message): bool { return $this->mailer->send($to, $subject, $message); }}2.2. Eliminación de variables globales
Las variables globales ($GLOBALS, $_SESSION directamente) son la principal fuente de errores. Utilice el patrón Registry o inyección de dependencias (DI).
// Malo: trabajo directo con variables globalesfunction getCurrentUser() { global $db; $id = $_SESSION['user_id']; return $db->query("SELECT * FROM users WHERE id = $id");}
// Bueno: inyección explícita de dependenciasclass UserProvider { public function __construct( private PDO $db, private SessionInterface $session ) {} public function getCurrentUser(): ?User { $id = $this->session->get('user_id'); return $this->db->query('SELECT * FROM users WHERE id = ?', [$id]); }}3. Reemplazo seguro de construcciones obsoletas
PHP evoluciona, y muchas construcciones antiguas se han vuelto inseguras y